diff options
| author | Murilo Ijanc <[email protected]> | 2026-07-27 20:37:05 -0300 |
|---|---|---|
| committer | Murilo Ijanc <[email protected]> | 2026-07-27 20:44:20 -0300 |
| commit | eb15ec9b2715783fcd2bf4f834595d1bd549c09d (patch) | |
| tree | cd9c6e80892b409db346fde3fe8334f3c37a1130 /README.md | |
| parent | e2c6ae13af335b311da2429c903032124f926df2 (diff) | |
| download | c-eb15ec9b2715783fcd2bf4f834595d1bd549c09d.tar.gz | |
A CEP that fails is rarely a random number. It is usually someone who
knows the city and guessed the last digits, and the classic guess is the
-000 that 957 municipalities never received. The API now answers those
404s with a faixa block naming the municipality the CEP would have
belonged to, and telling a caller "that CEP does not exist, did you mean
somewhere in Areal/RJ?" is worth far more than telling them "no".
It rides on cepis_error_t rather than on cepis_address_t because it is
context for a failure, not an address: the lookup still returns
CEPIS_ERR_NOT_FOUND and still hands back no address. Embedded by value
with a has_faixa flag, so the error keeps owning nothing and keeps
living on the stack with nothing to free; cepis_error_faixa gives the
absent case the same NULL-or-not shape as cepis_address_t::geo, which is
what the API's omit-never-null encoding calls for.
Parsing is total on purpose. A body that is not JSON, a faixa that is
null, a string, an array, or an object with no localidade all mean "the
API named no municipality". A 404 is already the answer, and failing to
read the garnish must never turn it into a different one.
The bounds need reading with care, hence the length of the comments:
cep_ini and cep_fim are the smallest and largest CEP that actually
exist, not the range the Correios publish -- the DNE's own start for
Areal is 25845000, exactly the CEP that just failed -- and the range is
sparse, 118 CEPs scattered over the ~4900 numbers up to 25849899. That
is what ceps is for.
Diffstat (limited to 'README.md')
| -rw-r--r-- | README.md | 62 |
1 files changed, 61 insertions, 1 deletions
@@ -41,6 +41,13 @@ make build sudo make install # PREFIX=/usr/local by default ``` +> **0.2.0 changed `sizeof(cepis_error_t)`** — it grew a `faixa` member. The +> source API is unchanged and existing code compiles untouched, but a program +> built against 0.1.0 must be **recompiled**, not just relinked: it declares +> the struct on its own stack at the old size, and the new library would write +> past the end of it. The soname went from `libcepis.so.0` to `libcepis.so.1` +> so the loader refuses that pairing instead of corrupting it silently. + Then compile against it: ```sh @@ -191,7 +198,7 @@ config.max_attempts = 3; /* counting the first; 1 disables retry */ config.backoff_base = 0.5; /* base of the exponential wait */ config.backoff_max = 8.0; /* cap on each wait */ config.total_timeout = 0.0; /* cap on the whole call; 0 = none */ -config.user_agent = NULL; /* NULL uses cepis-c/0.1.0 */ +config.user_agent = NULL; /* NULL uses cepis-c/0.2.0 */ cepis_client_new(&config, &client, &err); ``` @@ -251,6 +258,59 @@ default: 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. +### A CEP that does not exist + +A `CEPIS_ERR_NOT_FOUND` often knows more than "no". A CEP that fails is rarely +a random number — it is usually someone who knows the city and guessed the +last digits, and the classic guess is the `-000` that 957 municipalities never +received. So the error can name the municipality the CEP *would* have belonged +to: + +```c +const cepis_faixa_t *faixa; + +/* Still CEPIS_ERR_NOT_FOUND, still a 404. */ +cepis_lookup(client, "25845-000", &address, &err); + +faixa = cepis_error_faixa(&err); +if (faixa != NULL) { + faixa->localidade; /* "Areal" */ + faixa->uf; /* "RJ" */ + faixa->estado; /* "Rio de Janeiro" */ + faixa->regiao; /* "Sudeste" */ + faixa->ibge; /* "3300225" */ + faixa->cep_ini; /* "25845001" */ + faixa->cep_fim; /* "25849899" */ + faixa->ceps; /* 118 */ +} +``` + +Three things this is not: + +- **Not an address.** The CEP asked for still does not exist and the call + still failed. Never promote `faixa` to a delivery address, and never let it + turn a not-found into a success. Use it to say "that CEP does not exist — + did you mean somewhere in Areal/RJ?". +- **Not the range the Correios publish.** `cep_ini` and `cep_fim` are the + smallest and largest CEP that *actually exist* there. The DNE's own start + for Areal is `25845000` — exactly the CEP that just failed. `cep_ini` is + `25845001`, the first one really in the database. +- **Not a list.** The range is sparse: Areal's 118 CEPs are scattered across + the ~4900 numbers between `25845001` and `25849899`. Iterating the interval + mostly produces CEPs that do not exist either. That is what `ceps` is for — + say "118 CEPs in Areal", never "4899". + +`faixa` is **omitted, never null**, when the CEP falls in a band no +municipality owns, so `cepis_error_faixa` returning `NULL` — equivalently +`err.has_faixa == false` — is how you tell absent from present. A missing, +malformed or empty block leaves it absent and never changes the status: a 404 +is already the answer, and failing to read the garnish must not turn it into a +different one. + +`cepis_error_t` still owns nothing and still lives on the stack: `faixa` is +embedded by value, so there is nothing extra to free. The pointer +`cepis_error_faixa` returns is borrowed from the error and dies with it. + ## Development ```sh |