1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
/**
* 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);
}
|