diff options
| author | Murilo Ijanc <[email protected]> | 2026-07-27 20:39:06 -0300 |
|---|---|---|
| committer | Murilo Ijanc <[email protected]> | 2026-07-27 20:39:06 -0300 |
| commit | 497b1c1b01f6c9a584e5b40e02aff4763447529c (patch) | |
| tree | b50feb4252ba93cf045be3aaac14a96eeb04dff5 /README.md | |
| parent | 87166a5299aa551517a86379a0c05eb2110b52b0 (diff) | |
| download | zig-dc951ba530c9deed36233ffbfc2dd4a9478cabef.tar.gz | |
A CEP that fails to resolve is rarely a random number. It is almost always
someone who knows the city and guessed the digits, and the classic guess is
the -000 that 957 municipalities never received. The API now says so: a 404
carries an optional faixa block naming the municipality the number would have
belonged to, and answering "no such CEP in Areal/RJ, which has 118 of them" is
a great deal more useful than "not found".
It arrives through Diagnostics, which is where every other detail a Zig error
tag cannot carry already travels, and it is read with diag.faixa(). Like
message(), it lives in a fixed buffer inside the value and allocates nothing,
so no caller has to learn a new deinit for it.
The lookup still fails. faixa is context for the error, never an address, and
cep_ini/cep_fim are the smallest and largest CEP that actually exist there
rather than the bounds the Correios publish — for Areal the DNE's own start is
25845000, which is exactly the CEP that failed. The range is also sparse, 118
CEPs over ~4,900 numbers, so ceps is the count and the pair must never be
presented as a list. The doc comments and the README say all three, because
this field is easy to misread as a success.
Parsing is deliberately inert: a faixa that is missing, null, not an object,
nameless or oversized yields null, and an unreadable body is skipped. Nothing
about this field may promote a clean not-found into a parse failure.
Diffstat (limited to 'README.md')
| -rw-r--r-- | README.md | 56 |
1 files changed, 55 insertions, 1 deletions
@@ -200,7 +200,7 @@ to make**, not by the HTTP status that caused it: | error | when | does retrying help? | | --- | --- | --- | | `error.InvalidCep` | not 8 digits | no | -| `error.NotFound` | well-formed, not in the database | no | +| `error.NotFound` | well-formed, not in the database; `faixa` in the diagnostics | no | | `error.RateLimited` | 429; `retry_after_ms` in the diagnostics | yes, later | | `error.ServerError` | 5xx; `status` in the diagnostics | yes, later | | `error.NetworkError` | DNS, connection, timeout, TLS | yes, later | @@ -228,6 +228,60 @@ const address = client.lookup(cep_from_form, .{ .diagnostics = &diag }) catch |e 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. +### A CEP that does not exist + +`GET /{cep}` answers **404** for a CEP the DNE does not have, and this package +turns that into `error.NotFound`. When the number falls inside a band that +belongs to a municipality, the 404 also names it, and `diag.faixa()` gives you +that: + +```zig +var diag: cepis.Diagnostics = .{}; + +client.lookup("25845-000", .{ .diagnostics = &diag }) catch |err| switch (err) { + error.NotFound => { + if (diag.faixa()) |f| { + f.localidade; // "Areal" + f.uf; // "RJ" + f.estado; // "Rio de Janeiro" + f.regiao; // "Sudeste" + f.ibge; // "3300225" + f.cep_ini; // "25845001" + f.cep_fim; // "25849899" + f.ceps; // 118 + } + return askForAnotherCep(); + }, + else => return err, +}; +``` + +Worth having because a failing CEP is rarely random: it is someone who knows the +city and guessed the number, and the classic guess is the `-000` that 957 +municipalities never received — `25845000` above is exactly that guess for +Areal. + +> **It is still an error.** `faixa` explains *where* the number would have +> fallen. It is not an address, there is no address, and treating a non-null +> `faixa` as a successful lookup turns a clean failure into wrong data. + +Two things about the range, both of which make it wrong to hand it to a user as +a list of CEPs to try: + +- **`cep_ini` and `cep_fim` are not the Correios' bounds.** They are the + smallest and the largest CEP that *actually exist* in the municipality. The + DNE's own start for Areal is `25845000` — the CEP that just failed — while + `cep_ini` is `25845001`. +- **The range is sparse.** Areal's 118 CEPs are scattered over the ~4,900 + numbers between the two. That is what `ceps` is for; never compute + `cep_fim - cep_ini` and call it a count. + +`faixa()` is null whenever the API said nothing — the CEP fell in a band no +municipality owns, and there the field is **omitted**, never sent as null. Null +is the ordinary case, not a sign of trouble. Like `message()`, the value borrows +the `Diagnostics` and is valid only as long as it is; nothing is allocated and +there is nothing to free. + ## Development Everything runs through `make`, which shells out to `zig`: |