/** * D client for the public CEP API at $(LINK https://cep.is). Official Correios * data (DNE), refreshed every two weeks. * * Quick use — for a script, the module-level functions are enough: * * --- * import cepis; * * auto address = lookup("01001-000"); * writeln(address.localidade, " ", address.uf); // São Paulo SP * --- * * In an application — build a $(D Client) once and reuse it: * * --- * ClientConfig config; * config.timeout = dur!"seconds"(5); * config.totalTimeout = dur!"seconds"(15); * * auto client = Client(config); * auto address = client.lookup("01001000"); * --- * * Pointing at a local instance (the API repo brings one up with `just up`): * * --- * ClientConfig config; * config.baseUrl = "http://localhost:8080"; * auto client = Client(config); * --- * * Errors are explicit and split by decision — whether retrying helps or not: * * --- * try * render(lookup(cepFromForm)); * catch (CepNotFoundException) * askForAnotherCep(); // the CEP does not exist * catch (CepisException error) * if (error.retriable) reschedule(); // network, server, rate limit * --- * * A not-found sometimes knows where the CEP $(I would) have been — see * $(D CepNotFoundException.faixa) and $(D Faixa). That is context for the * error, never an address. * * Note on field names: the API surface is English, but the $(B data fields keep * the API's own Portuguese names) ($(D logradouro), $(D bairro), * $(D localidade)). What you read in the JSON is what you access on the value. * * The module-level functions share one default client per thread, built on * first use. Anyone needing different settings should build their own * $(D Client). */ module cepis; public import cepis.client; public import cepis.exception; public import cepis.model; import std.typecons : Nullable; @safe: /** * Look up a CEP using the default configuration. * * Shorthand for `Client(ClientConfig.init).lookup(cep)`; see $(D Client.lookup). */ Address lookup(scope const(char)[] cep) { return defaultClient().lookup(cep); } /** * Look up many CEPs in one batch, using the default configuration. * * Shorthand for $(D Client.lookupMany) — read that one, especially the warning * that batches carry no coordinate. */ Nullable!Address[] lookupMany(scope const(string)[] ceps) { return defaultClient().lookupMany(ceps); } /** * Query the API's health using the default configuration. * * Shorthand for $(D Client.health). */ Health health() { return defaultClient().health(); } private Client defaultClient() { static Client instance; static bool built; if (!built) { instance = Client(ClientConfig.init); built = true; } return instance; } @("the default client is built once and points at the public API") unittest { assert(defaultClient().baseUrl == DEFAULT_URL); assert(defaultClient().maxAttempts == 3); }