summaryrefslogtreecommitdiffstats
path: root/models.go
diff options
context:
space:
mode:
authorMurilo Ijanc <[email protected]>2026-07-27 20:15:36 -0300
committerMurilo Ijanc <[email protected]>2026-07-27 20:23:14 -0300
commit47c822d0d5e690092617b6170972917058a6d45d (patch)
tree583ce076573d29a60dc8453df7089022458b7303 /models.go
parent323d9a8422f06676d25cdf890c06962b260cb8aa (diff)
downloadgo-47c822d0d5e690092617b6170972917058a6d45d.tar.gz
Carry the municipality of a CEP that does not existHEADv0.2.0main
A 404 that only says "not found" is correct and useless. The CEP that fails is almost never random: it is someone who knows the city and guessed the number, and the classic guess is the -000 that 957 municipalities never received. The API now names the municipality on the 404, so surface it as Error.Faixa instead of throwing the body away.
Diffstat (limited to 'models.go')
-rw-r--r--models.go47
1 files changed, 47 insertions, 0 deletions
diff --git a/models.go b/models.go
index 3d21bf8..f5eabaa 100644
--- a/models.go
+++ b/models.go
@@ -35,6 +35,33 @@ func (g Geo) IsPrecise() bool {
return g.Precisao == "logradouro"
}
+// Faixa is the municipality a CEP that does not exist would belong to, and the
+// range of CEPs that municipality actually has. It arrives on the 404, hanging
+// off [Error.Faixa].
+//
+// A CEP that fails is rarely a random number. It is usually someone who knows
+// the city and guessed the rest, and the classic guess is the "-000": a small
+// town often has a single city-wide CEP ending that way, but 957 municipalities
+// are coded street by street and never got one. Areal/RJ answers from
+// 25845-001 up, never at 25845-000 — so the 404 for 25845000 names Areal.
+//
+// CEPIni and CEPFim are the smallest and the largest CEP that EXIST in that
+// municipality, not the bounds the Correios publish. Do not read the pair as a
+// list of valid CEPs: the range is sparse, which is what CEPs is for — Areal's
+// 118 CEPs are scattered across nearly five thousand numbers.
+type Faixa struct {
+ Localidade string `json:"localidade"`
+ UF string `json:"uf"`
+ Estado string `json:"estado"`
+ Regiao string `json:"regiao"`
+ IBGE string `json:"ibge"`
+ CEPIni string `json:"cep_ini"`
+ CEPFim string `json:"cep_fim"`
+
+ // CEPs is how many CEPs the municipality actually has inside the range.
+ CEPs int `json:"ceps"`
+}
+
// Address is a CEP and everything the database knows about it.
//
// The field names are the API's own, in Portuguese, with only the casing
@@ -147,6 +174,26 @@ func decodeGeo(block json.RawMessage) *Geo {
}
}
+// decodeFaixa reads the `faixa` block of a 404 body. Every failure — absent
+// block, malformed JSON, a `faixa` without a locality — yields nil: the field
+// is an extra on top of an error that is already complete without it, and it
+// must never turn a clean ErrCEPNotFound into a parse failure.
+func decodeFaixa(body []byte) *Faixa {
+ if len(body) == 0 {
+ return nil
+ }
+ var envelope struct {
+ Faixa *Faixa `json:"faixa"`
+ }
+ if err := json.Unmarshal(body, &envelope); err != nil {
+ return nil
+ }
+ if envelope.Faixa == nil || envelope.Faixa.Localidade == "" {
+ return nil
+ }
+ return envelope.Faixa
+}
+
func rawString(value json.RawMessage) string {
if len(value) == 0 {
return ""