summaryrefslogtreecommitdiffstats
path: root/include/cepis/models.hpp
diff options
context:
space:
mode:
authorMurilo Ijanc <[email protected]>2026-07-26 12:28:10 -0300
committerMurilo Ijanc <[email protected]>2026-07-26 12:28:10 -0300
commitb71faa6e95a0736f1ff171e006b171467b65db90 (patch)
tree7580c3ab515e8f50726dc68dbc240995ff4a1a4c /include/cepis/models.hpp
downloadcpp-b71faa6e95a0736f1ff171e006b171467b65db90.tar.gz
Initial importv0.1.0
Diffstat (limited to 'include/cepis/models.hpp')
-rw-r--r--include/cepis/models.hpp120
1 files changed, 120 insertions, 0 deletions
diff --git a/include/cepis/models.hpp b/include/cepis/models.hpp
new file mode 100644
index 0000000..faa2dde
--- /dev/null
+++ b/include/cepis/models.hpp
@@ -0,0 +1,120 @@
+#ifndef CEPIS_MODELS_HPP
+#define CEPIS_MODELS_HPP
+
+#include <cstdint>
+#include <optional>
+#include <string>
+
+#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> 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