summaryrefslogtreecommitdiffstats
path: root/README.md
diff options
context:
space:
mode:
authorMurilo Ijanc <[email protected]>2026-07-27 20:32:01 -0300
committerMurilo Ijanc <[email protected]>2026-07-27 20:32:01 -0300
commitb402de683eecef4c890081dd72edbcaf57f375e0 (patch)
tree13e184ad13b3cad394e5c84c25b48df3b2052781 /README.md
parent36a0ddb01a4fcb8fb2fefd7c407ecca0e3e56e7c (diff)
downloadruby-84a6d224754979f76ce590e0175b9b939438a36f.tar.gz
Expose the band of a CEP that does not existHEADv0.2.0main
A CEP that fails a lookup is rarely a random number: it is someone who knows the city and guessed the digits, most often the -000 that 957 municipalities never received. The API now answers that 404 with an optional faixa naming the municipality those numbers belong to, so the caller can say "not found, but you seem to be looking at Areal/RJ" instead of just "not found". It stays an error. Faixa hangs off CEPNotFound and nothing about it promotes a nonexistent CEP into an address. Its cep_ini/cep_fim are the smallest and largest CEP that really exist there, not the published bounds — the DNE's own start for Areal is the CEP that just failed — and the band is sparse, which is what ceps is for; both facts are spelled out in the docs so nobody iterates the pair. Parsing is deliberately toothless: a missing, empty or malformed faixa, or a 404 body that is not JSON at all, all yield nil. Losing the consolation prize must never replace a clean not-found with a parse failure.
Diffstat (limited to 'README.md')
-rw-r--r--README.md44
1 files changed, 44 insertions, 0 deletions
diff --git a/README.md b/README.md
index 017fe89..0085f1c 100644
--- a/README.md
+++ b/README.md
@@ -180,6 +180,50 @@ end
`RateLimited#retry_after` carries what the server asked for, in seconds, and
`ServerError#status` the HTTP status of the last attempt.
+### The band of a CEP that does not exist
+
+A CEP that fails is rarely a random number: it is usually someone who knows
+the city and guessed the digits. The classic guess is the `-000`, which 957
+municipalities never received.
+
+So the 404 tries to say something useful. When the numbers around the one you
+asked for belong to a municipality, `CEPNotFound#faixa` names it:
+
+```ruby
+begin
+ Cepis.lookup("25845-000")
+rescue Cepis::CEPNotFound => e
+ if e.faixa
+ puts e.faixa.localidade # "Areal"
+ puts e.faixa.uf # "RJ"
+ puts e.faixa.ibge # "3300225"
+ puts e.faixa.ceps # 118
+ puts e.faixa.cep_ini # "25845001"
+ puts e.faixa.cep_fim # "25849899"
+ end
+end
+```
+
+Three things about it, all of which are easy to get wrong:
+
+- **It is still a 404.** `faixa` is context for the failure, not a fallback
+ address. The CEP asked for does not exist; do not save it, do not ship to
+ it. It is for the error message, the log line and the "did you mean
+ somewhere in Areal?" prompt.
+- **`cep_ini` and `cep_fim` are the smallest and the largest CEP that actually
+ exist there**, not the bounds the Correios publish. The DNE's own start for
+ Areal is `25845000` — exactly the CEP that just failed, which is why the
+ published bounds would be useless here.
+- **The band is sparse.** Areal's 118 CEPs are scattered across the ~4,900
+ numbers between `25845001` and `25849899`. That is what `ceps` is for. The
+ pair is not a range of valid CEPs, and iterating it produces about fifty
+ nonexistent numbers for each real one.
+
+`faixa` is `nil` when the CEP falls in a band no municipality owns — the API
+**omits** the field there, it never sends null — and also when the 404 body is
+unreadable. Reading it can never fail loudly: a not-found stays a clean
+`CEPNotFound`, never an `InvalidResponse`.
+
`InvalidResponse` almost always means something between you and the API is
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.