#ifndef CEPIS_MODELS_HPP #define CEPIS_MODELS_HPP #include #include #include #include "cepis/json.hpp" /// The data the API returns, as values. /// /// **Field names are the API's own, in Portuguese** — `logradouro`, `bairro`, /// `localidade`. Everything else in this library is English; the fields are the /// one deliberate exception. /// /// The reason is fidelity: what you read in the JSON at https://cep.is/01001000 /// is exactly what you access on the object. Translating to `street`/`city` /// would mean maintaining a field-by-field mapping and forcing anyone reading /// the API docs alongside this library to translate back in their head. The /// values are Portuguese either way — they come from the Correios database. namespace cepis { /// The CEP's coordinate, when the database has one. /// /// The point is the **median** of the coordinates of that CEP's addresses, not /// the mean: one badly geocoded address 40 km away shifts a mean and does not /// move a median. /// /// Always check `precisao` before using `lat`/`lon` for distance: /// /// - `"logradouro"`: the point is a stretch of street. `raio_m` lands around /// 100–150 m. Good for maps and for distance. /// - `"localidade"`: the CEP *is* the whole municipality (a city-wide general /// CEP), and the point is its centroid. `raio_m` runs from 7 km to 40 km. /// Computing shipping from this is wrong by tens of kilometres. /// /// `raio_m` is the radius containing 90% of that CEP's addresses. It exists /// precisely so that error cannot pass unnoticed. struct Geo { double lat = 0.0; double lon = 0.0; std::int64_t raio_m = 0; std::string precisao; /// `true` when the coordinate points at a street, not a municipality. /// /// Shorthand for `precisao == "logradouro"`, which is the check to make /// before using the point to measure distance. [[nodiscard]] bool is_precise() const noexcept { return precisao == "logradouro"; } }; /// A CEP and everything the database knows about it. /// /// Fields the database does not have for that CEP come back as empty strings, /// never absent — that is what the API returns, and changing it here would /// create a difference between reading the JSON and reading this library. /// /// `geo` is the exception: it is `std::nullopt` when there is no coordinate. /// There the difference is real, because the API **omits** the whole field in /// that case (about 43% of CEPs) rather than sending null. struct Address { std::string cep; std::string logradouro; std::string complemento; std::string unidade; std::string bairro; std::string localidade; std::string uf; std::string estado; std::string regiao; std::string ibge; std::string gia; std::string ddd; std::string siafi; std::optional geo; /// The response exactly as it arrived, uninterpreted, so a field the API /// grows before this library is updated is not lost. Json raw; /// The CEP with its mask: `01001-000`. /// /// The native contract always returns it unmasked; formatting is /// presentation, and it lives here so it does not become a repeated /// concatenation in every project that uses this. [[nodiscard]] std::string formatted_cep() const; /// Builds from the object the API returned. /// /// Unknown fields are ignored during construction but preserved in `raw`. A /// new field in the API therefore cannot break this library. /// /// A malformed `geo` block yields an empty `geo` rather than propagating the /// error: it is not worth losing the whole address over, since the rest of /// the response is still useful. static Address from_json(const Json& data); }; /// The response of `GET /health`. /// /// Good for two things: checking that the API answers, and knowing **which /// version of the database** is live. The DNE database changes every two /// weeks; `dne` identifies it. struct Health { std::string status; std::string dne; std::int64_t ceps = 0; std::int64_t geo = 0; std::string base_gerada_em; /// `true` when the API reports itself healthy. [[nodiscard]] bool ok() const noexcept { return status == "ok"; } /// Builds from the object the API returned. static Health from_json(const Json& data); }; } // namespace cepis #endif // CEPIS_MODELS_HPP