summaryrefslogtreecommitdiffstats
path: root/README.md
diff options
context:
space:
mode:
authorMurilo Ijanc <[email protected]>2026-07-27 20:33:24 -0300
committerMurilo Ijanc <[email protected]>2026-07-27 20:33:24 -0300
commitd7ca2d6f4b1c5c1f5f1b6ce6ffad35aaffee5b0f (patch)
tree21aca875c28f4d7d9ec3b0a807e7c7f15a6766d8 /README.md
parent72a4b451c9d06f7a97cac2f43f1b7f52fafcd3b7 (diff)
downloadswift-d7ca2d6f4b1c5c1f5f1b6ce6ffad35aaffee5b0f.tar.gz
Carry the municipality on a not-found CEPHEADv0.2.0main
A CEP that fails a lookup is rarely a random number: it is almost always someone who knows the city and guessed the digits. The classic guess is the -000, which 957 municipalities never received. Answering that with a bare "not found" throws away what the API knows — that the number is in Areal/RJ's band — and leaves the caller unable to tell a typo apart from a city that has no such CEP. The 404 now carries an optional faixa, so cepNotFound carries it too. It decorates the error and never replaces it: the CEP still does not exist and the call still throws. Parsing is deliberately incapable of escalating — a faixa that is absent, null, empty or malformed becomes nil, because losing the decoration must never cost the clean not-found underneath it. Faixa offers no contains(): cep_ini and cep_fim are the smallest and largest CEP that actually exist, not the bounds the Correios publish, and the range between them is sparse — Areal's 118 CEPs are spread over some 4,900 numbers. Only a lookup can answer whether a CEP exists, and an API that appeared to answer it from the pair would be lying. Widening cepNotFound's payload breaks anyone matching the case with a single binding, hence 0.2.0.
Diffstat (limited to 'README.md')
-rw-r--r--README.md50
1 files changed, 48 insertions, 2 deletions
diff --git a/README.md b/README.md
index 7d75a9c..f92d208 100644
--- a/README.md
+++ b/README.md
@@ -20,7 +20,7 @@ Add the package to `Package.swift`:
```swift
dependencies: [
- .package(url: "https://git.cep.is/swift.git", from: "0.1.0")
+ .package(url: "https://git.cep.is/swift.git", from: "0.2.0")
]
```
@@ -169,7 +169,7 @@ make**, not by the HTTP status that caused them:
| case | when | does retrying help? |
| --- | --- | --- |
| `invalidCEP` | not 8 digits | no |
-| `cepNotFound` | well-formed, not in the database | no |
+| `cepNotFound` | well-formed, not in the database; carries `faixa` | no |
| `rateLimited` | 429; carries `retryAfter` | yes, later |
| `serverError` | 5xx; carries `status` | yes, later |
| `networkError` | DNS, connection, timeout, TLS | yes, later |
@@ -190,6 +190,52 @@ do {
answering instead of it — a captive Wi-Fi portal, a corporate proxy, an HTML
error page. Useful as a diagnosis: the problem is not in your code.
+### Which city the missing CEP belonged to
+
+A CEP that fails is rarely a random number. It is usually someone who knows the
+city and guessed the digits — and the classic guess is the `-000`, which 957
+municipalities never received.
+
+So `cepNotFound` carries a `Faixa`: the municipality the CEP *would* have
+belonged to, when the API can say.
+
+```swift
+do {
+ let address = try await Client.shared.lookup("25845-000")
+} catch CepisError.cepNotFound(let message, let faixa) {
+ if let faixa {
+ print("\(message) — that range is \(faixa.localidadeUF)")
+ // … does not exist in the DNE database — that range is Areal/RJ
+ faixa.ibge // "3300225"
+ faixa.cepIni // "25845001"
+ faixa.cepFim // "25849899"
+ faixa.ceps // 118
+ }
+}
+```
+
+`error.faixa` reaches the same value without pattern-matching, and
+`error.description` (and `errorDescription`) already names the municipality when
+there is one. `error.message` stays exactly what it was.
+
+Three things to keep straight:
+
+- **It is still a 404.** The CEP does not exist. A `Faixa` is context for the
+ error, never an address — it can turn *"not found"* into *"not a CEP, but you
+ are looking at Areal/RJ"*, and nothing more.
+- **`cepIni`/`cepFim` are not the Correios' published bounds.** They are the
+ smallest and largest CEP that *actually exist* there. The DNE's own start for
+ Areal is `25845000` — precisely the CEP that just failed. `cepIni` is
+ `25845001`.
+- **The range is sparse.** It is not a list of valid CEPs and iterating it is
+ wrong: Areal's 118 CEPs are scattered across the ~4,900 numbers between the
+ two bounds, about one in forty. That is what `ceps` is for.
+
+The field is **omitted, never null**, when the CEP falls in a band no
+municipality owns, so `faixa == nil` is ordinary and must be handled. It is also
+`nil` when the response could not be understood: a malformed `faixa` never
+escalates a clean not-found into a decoding failure.
+
## Development
```sh