summaryrefslogtreecommitdiffstats
path: root/man
diff options
context:
space:
mode:
authorMurilo Ijanc <[email protected]>2026-07-26 12:42:37 -0300
committerMurilo Ijanc <[email protected]>2026-07-26 12:42:37 -0300
commit11d49bc25eb1643f1b742f9527212d8781f2e0de (patch)
treebae1cb090cbf6c9f82ab5abbaf1194206f92f539 /man
downloadr-11d49bc25eb1643f1b742f9527212d8781f2e0de.tar.gz
Initial importv0.1.0
Diffstat (limited to 'man')
-rw-r--r--man/cep_health.Rd34
-rw-r--r--man/cep_lookup.Rd46
-rw-r--r--man/cep_lookup_many.Rd51
-rw-r--r--man/cepis-package.Rd38
-rw-r--r--man/cepis_address.Rd34
-rw-r--r--man/cepis_client.Rd64
-rw-r--r--man/cepis_conditions.Rd42
-rw-r--r--man/cepis_geo.Rd36
-rw-r--r--man/cepis_health.Rd23
-rw-r--r--man/formatted_cep.Rd25
-rw-r--r--man/normalize_cep.Rd33
11 files changed, 426 insertions, 0 deletions
diff --git a/man/cep_health.Rd b/man/cep_health.Rd
new file mode 100644
index 0000000..7fdfc1b
--- /dev/null
+++ b/man/cep_health.Rd
@@ -0,0 +1,34 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/api.R
+\name{cep_health}
+\alias{cep_health}
+\title{Ask the API how it is, and which database it is serving}
+\usage{
+cep_health(client = default_client())
+}
+\arguments{
+\item{client}{A \code{\link[=cepis_client]{cepis_client()}}. Defaults to a shared client built with
+the default configuration.}
+}
+\value{
+A \link{cepis_health}.
+}
+\description{
+Useful for two things: checking that the API answers, and knowing which
+version of the DNE database is live. The database changes every two weeks.
+}
+\section{Conditions}{
+
+An API reporting itself degraded is not a failure here — that arrives in
+\code{status}, and checking health is exactly when you want the diagnosis
+rather than an error. Network failures still signal \code{cepis_network_error}.
+}
+
+\examples{
+\donttest{
+health <- cep_health()
+health$ok
+health$dne
+}
+
+}
diff --git a/man/cep_lookup.Rd b/man/cep_lookup.Rd
new file mode 100644
index 0000000..3c22a1e
--- /dev/null
+++ b/man/cep_lookup.Rd
@@ -0,0 +1,46 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/api.R
+\name{cep_lookup}
+\alias{cep_lookup}
+\title{Look up a single CEP}
+\usage{
+cep_lookup(cep, client = default_client())
+}
+\arguments{
+\item{cep}{A length-one character vector: \code{"01001-000"} or \code{"01001000"}.}
+
+\item{client}{A \code{\link[=cepis_client]{cepis_client()}}. Defaults to a shared client built with
+the default configuration.}
+}
+\value{
+A \link{cepis_address}.
+}
+\description{
+Accepts the CEP masked or unmasked and returns everything the DNE database
+has for it, including the coordinate when there is one.
+}
+\section{Conditions}{
+
+\describe{
+\item{\code{cepis_invalid_cep}}{the CEP is not 8 digits. No request is made.}
+\item{\code{cepis_not_found}}{well-formed, but not in the database.}
+\item{\code{cepis_rate_limited}}{429 on every attempt.}
+\item{\code{cepis_server_error}}{5xx on every attempt.}
+\item{\code{cepis_network_error}}{the request never completed.}
+\item{\code{cepis_invalid_response}}{a success status with an unreadable
+body.}
+}
+
+All of them inherit \code{cepis_error}; see \link{cepis_conditions}.
+}
+
+\examples{
+\donttest{
+address <- cep_lookup("01001-000")
+address$localidade
+if (!is.null(address$geo) && address$geo$is_precise) {
+ c(address$geo$lat, address$geo$lon)
+}
+}
+
+}
diff --git a/man/cep_lookup_many.Rd b/man/cep_lookup_many.Rd
new file mode 100644
index 0000000..9362649
--- /dev/null
+++ b/man/cep_lookup_many.Rd
@@ -0,0 +1,51 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/api.R
+\name{cep_lookup_many}
+\alias{cep_lookup_many}
+\title{Look up many CEPs in one request}
+\usage{
+cep_lookup_many(ceps, client = default_client())
+}
+\arguments{
+\item{ceps}{A character vector of CEPs, masked or unmasked.}
+
+\item{client}{A \code{\link[=cepis_client]{cepis_client()}}. Defaults to a shared client built with
+the default configuration.}
+}
+\value{
+A list of \strong{the same length and in the same order} as \code{ceps}.
+Each element is a \link{cepis_address}, or \code{NULL} where the CEP does not
+exist or is malformed — it does not vanish from the list, and it does not
+signal a condition. That is the right difference from \code{\link[=cep_lookup]{cep_lookup()}}: in
+a batch of a thousand, one bad CEP must not cost the other nine hundred
+and ninety-nine. Use \code{\link[=normalize_cep]{normalize_cep()}} beforehand if you need to know
+\emph{which} input was malformed.
+
+A list rather than a \code{data.frame} because \code{NULL} is the only unambiguous
+"no such CEP" in R: a row of \code{NA}s reads as an address with unknown
+fields, which is a different statement, and an empty row cannot be told
+apart from a CEP the database knows only by number. Rectangle it with
+\code{do.call(rbind, lapply(result, function(a) as.data.frame(a[1:13])))} when
+a \code{data.frame} is what you want.
+}
+\description{
+Resolves up to 500 CEPs per request, chunking longer inputs automatically.
+Do not loop over \code{\link[=cep_lookup]{cep_lookup()}}: a loop of 500 calls pays 500 TLS
+handshakes, the batch pays one.
+}
+\section{Batches carry no coordinate}{
+
+The endpoint behind them is CSV, and the CSV has no \code{geo} column. Every
+address returned here has \code{geo = NULL}, including for CEPs that do have
+one. Need \code{geo}? Use \code{\link[=cep_lookup]{cep_lookup()}}, one at a time.
+}
+
+\examples{
+\donttest{
+ceps <- c("01001000", "99999999", "20040020")
+result <- cep_lookup_many(ceps)
+vapply(result, function(a) if (is.null(a)) NA_character_ else a$localidade,
+ character(1))
+}
+
+}
diff --git a/man/cepis-package.Rd b/man/cepis-package.Rd
new file mode 100644
index 0000000..d182e04
--- /dev/null
+++ b/man/cepis-package.Rd
@@ -0,0 +1,38 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/cepis-package.R
+\docType{package}
+\name{cepis-package}
+\alias{cepis}
+\alias{cepis-package}
+\title{cepis: client for the public CEP API at cep.is}
+\description{
+Resolves Brazilian postal codes against \url{https://cep.is}. Official
+Correios data (DNE), refreshed every two weeks.
+
+\if{html}{\out{<div class="sourceCode r">}}\preformatted{address <- cep_lookup("01001-000")
+address$logradouro # "Praca da Se"
+address$localidade # "Sao Paulo"
+}\if{html}{\out{</div>}}
+
+The API surface is English, but the \strong{data fields keep the API's own
+Portuguese names} (\code{logradouro}, \code{bairro}, \code{localidade}, \code{uf}). What you
+read in the JSON at \url{https://cep.is/01001000} is what you read on the
+returned object, with no translation layer in between.
+
+Start at \code{\link[=cep_lookup]{cep_lookup()}} for one CEP, \code{\link[=cep_lookup_many]{cep_lookup_many()}} for many,
+\code{\link[=cep_health]{cep_health()}} for the API's status and \code{\link[=cepis_client]{cepis_client()}} for anything
+beyond the default configuration. Failures are classed conditions,
+described in \link{cepis_conditions}.
+}
+\seealso{
+Useful links:
+\itemize{
+ \item \url{https://cep.is}
+}
+
+}
+\author{
+\strong{Maintainer}: Murilo Ijanc \email{[email protected]}
+
+}
+\keyword{internal}
diff --git a/man/cepis_address.Rd b/man/cepis_address.Rd
new file mode 100644
index 0000000..6fc0b89
--- /dev/null
+++ b/man/cepis_address.Rd
@@ -0,0 +1,34 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/models.R
+\name{cepis_address}
+\alias{cepis_address}
+\title{A CEP and everything the database knows about it}
+\description{
+The object returned by \code{\link[=cep_lookup]{cep_lookup()}} and by each element of
+\code{\link[=cep_lookup_many]{cep_lookup_many()}}. It is a plain list of class \code{cepis_address}, so
+\code{address$localidade} and \code{str(address)} work as usual.
+
+\strong{The data fields keep the API's Portuguese names.} Fields the database
+does not have for a CEP come back as empty strings, never \code{NA} — that is
+what the API returns, and changing it here would create a difference
+between reading the JSON and reading this package.
+}
+\section{Fields}{
+
+\describe{
+\item{\code{cep}}{the 8 digits, always unmasked. \code{\link[=formatted_cep]{formatted_cep()}} adds the
+mask.}
+\item{\code{logradouro}, \code{complemento}, \code{unidade}, \code{bairro}}{the street and
+its qualifiers.}
+\item{\code{localidade}, \code{uf}, \code{estado}, \code{regiao}}{municipality, state code,
+state name, region.}
+\item{\code{ibge}, \code{gia}, \code{ddd}, \code{siafi}}{the codes the database carries.}
+\item{\code{geo}}{a \link{cepis_geo} object, or \code{NULL} when the database has no
+coordinate for that CEP. \code{NULL} and not a row of \code{NA}s because the API
+\strong{omits} the whole field in that case (about 43\% of CEPs) rather than
+sending null.}
+\item{\code{raw}}{the response exactly as it arrived, uninterpreted, so a
+field the API grows before this package is updated is not lost.}
+}
+}
+
diff --git a/man/cepis_client.Rd b/man/cepis_client.Rd
new file mode 100644
index 0000000..f8644e7
--- /dev/null
+++ b/man/cepis_client.Rd
@@ -0,0 +1,64 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/client.R
+\name{cepis_client}
+\alias{cepis_client}
+\title{Build a client for the cep.is API}
+\usage{
+cepis_client(
+ base_url = DEFAULT_BASE_URL,
+ timeout = 10,
+ max_attempts = 3L,
+ backoff_base = 0.5,
+ backoff_max = 8,
+ total_timeout = NULL,
+ user_agent = NULL
+)
+}
+\arguments{
+\item{base_url}{Where the API lives. Point it at a local instance (the API
+repo brings one up on \verb{http://localhost:8080} with \verb{just up}) or at a
+test server. It is the only parameter that usually changes between
+environments. Trailing slashes are stripped, so it cannot produce
+doubled separators that some proxies normalise and others 404.}
+
+\item{timeout}{Seconds allowed for \strong{one attempt}, connection and
+transfer together. It is not a cap on the whole call, since a call may
+make several attempts; that cap is \code{total_timeout}.}
+
+\item{max_attempts}{How many attempts in total, counting the first. \code{1}
+disables retrying. The default of \code{3} covers the common case (one
+transient failure) without turning a real outage into a long wait.}
+
+\item{backoff_base}{Base of the exponential wait, in seconds. The actual
+wait is drawn from \verb{[0, base * 2^(n - 1)]} — \emph{full jitter}. The
+randomness is not decoration: without it, N clients that fail together
+come back together and reproduce the spike that took the service down.}
+
+\item{backoff_max}{Cap on each individual wait, in seconds. It applies to
+a server-sent \code{Retry-After} too, or a \code{Retry-After: 3600} from a
+misconfigured proxy would park the session for an hour.}
+
+\item{total_timeout}{Cap on the whole call, attempts and waits included.
+\code{NULL} leaves \code{max_attempts} as the only bound. Set it in code serving a
+web request: without it the worst case is \code{max_attempts * timeout} plus
+the sum of the backoffs.}
+
+\item{user_agent}{Overrides the \code{User-Agent}. The default identifies the
+package and its version, which is what lets the server diagnose an old
+client misbehaving.}
+}
+\value{
+An object of class \code{cepis_client}, to pass as the \code{client}
+argument of \code{\link[=cep_lookup]{cep_lookup()}}, \code{\link[=cep_lookup_many]{cep_lookup_many()}} and \code{\link[=cep_health]{cep_health()}}.
+}
+\description{
+Holds the configuration and nothing else: no connection, no state between
+calls. Build one and reuse it, or skip it entirely — \code{\link[=cep_lookup]{cep_lookup()}},
+\code{\link[=cep_lookup_many]{cep_lookup_many()}} and \code{\link[=cep_health]{cep_health()}} fall back to a shared default
+client built with these defaults.
+}
+\examples{
+client <- cepis_client(base_url = "http://localhost:8080", timeout = 5)
+client$max_attempts
+
+}
diff --git a/man/cepis_conditions.Rd b/man/cepis_conditions.Rd
new file mode 100644
index 0000000..4def4ff
--- /dev/null
+++ b/man/cepis_conditions.Rd
@@ -0,0 +1,42 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/conditions.R
+\name{cepis_conditions}
+\alias{cepis_conditions}
+\title{Conditions signalled by cepis}
+\description{
+Every failure raised by this package is a classed condition inheriting
+from \code{cepis_error}, so one handler catches all of them:
+
+\if{html}{\out{<div class="sourceCode r">}}\preformatted{tryCatch(
+ cep_lookup(cep_from_form),
+ cepis_not_found = function(e) NULL,
+ cepis_error = function(e) reschedule()
+)
+}\if{html}{\out{</div>}}
+
+Below \code{cepis_error} the split is by \strong{the decision you have to make}, not
+by the HTTP status that caused it:\tabular{lll}{
+ class \tab when \tab does retrying help? \cr
+ \code{cepis_invalid_cep} \tab not 8 digits \tab no \cr
+ \code{cepis_not_found} \tab well-formed, not in the database \tab no \cr
+ \code{cepis_rate_limited} \tab 429 \tab yes, later \cr
+ \code{cepis_server_error} \tab 5xx \tab yes, later \cr
+ \code{cepis_network_error} \tab DNS, connection, timeout, TLS \tab yes, later \cr
+ \code{cepis_invalid_response} \tab unintelligible response \tab probably not \cr
+}
+
+
+That split is why \code{cepis_not_found} is not "the HTTP 404 condition": it is
+also signalled with no request made at all, when the CEP is malformed
+before it ever leaves the machine.
+
+Each condition carries the fields a caller needs to act on it:
+\code{cepis_rate_limited} has \code{retry_after} (seconds the server asked for, or
+\code{NULL}), \code{cepis_server_error} has \code{status}, \code{cepis_network_error} has
+\code{url}, and \code{cepis_invalid_cep} has \code{value}, the input as it arrived.
+
+\code{cepis_invalid_response} almost always means something between you and the
+API is answering instead of it — a captive Wi-Fi portal, a corporate
+proxy, an HTML error page. Useful as a diagnosis: the problem is not in
+your code.
+}
diff --git a/man/cepis_geo.Rd b/man/cepis_geo.Rd
new file mode 100644
index 0000000..3c92979
--- /dev/null
+++ b/man/cepis_geo.Rd
@@ -0,0 +1,36 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/models.R
+\name{cepis_geo}
+\alias{cepis_geo}
+\title{The coordinate of a CEP, when the database has one}
+\description{
+The \code{geo} field of a \link{cepis_address}, a plain list of class \code{cepis_geo}.
+The point is the \strong{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.
+}
+\section{Fields}{
+
+\describe{
+\item{\code{lat}, \code{lon}}{decimal degrees, WGS 84.}
+\item{\code{raio_m}}{the radius, in metres, containing 90\% of that CEP's
+addresses.}
+\item{\code{precisao}}{\code{"logradouro"} or \code{"localidade"} — see below.}
+\item{\code{is_precise}}{\code{TRUE} when \code{precisao} is \code{"logradouro"}. Derived,
+not sent by the API.}
+}
+}
+
+\section{Always check precisao before measuring distance}{
+
+There are two kinds of point, and the difference between them is tens of
+kilometres:\tabular{lll}{
+ \code{precisao} \tab typical \code{raio_m} \tab what the point is \cr
+ \code{logradouro} \tab 110-140 m \tab the stretch of street: good for maps and for distance \cr
+ \code{localidade} \tab 7-40 km \tab the municipality centroid, because the CEP \emph{is} the whole city \cr
+}
+
+
+\code{raio_m} exists precisely so that error cannot pass unnoticed.
+}
+
diff --git a/man/cepis_health.Rd b/man/cepis_health.Rd
new file mode 100644
index 0000000..dc00d8b
--- /dev/null
+++ b/man/cepis_health.Rd
@@ -0,0 +1,23 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/models.R
+\name{cepis_health}
+\alias{cepis_health}
+\title{The answer of \code{GET /health}}
+\description{
+A plain list of class \code{cepis_health}, returned by \code{\link[=cep_health]{cep_health()}}. Good for
+two things: checking that the API answers, and knowing \strong{which version of
+the database} is live. The DNE database changes every two weeks; \code{dne}
+identifies it.
+}
+\section{Fields}{
+
+\describe{
+\item{\code{status}}{\code{"ok"} when the API reports itself healthy.}
+\item{\code{ok}}{\code{status == "ok"}. Derived, not sent by the API.}
+\item{\code{dne}}{identifier of the fortnightly database.}
+\item{\code{ceps}}{how many CEPs it holds.}
+\item{\code{geo}}{how many of those carry a coordinate.}
+\item{\code{base_gerada_em}}{when the base was generated, UTC.}
+}
+}
+
diff --git a/man/formatted_cep.Rd b/man/formatted_cep.Rd
new file mode 100644
index 0000000..7f77b4e
--- /dev/null
+++ b/man/formatted_cep.Rd
@@ -0,0 +1,25 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/models.R
+\name{formatted_cep}
+\alias{formatted_cep}
+\title{Add the mask to a CEP}
+\usage{
+formatted_cep(x)
+}
+\arguments{
+\item{x}{A \link{cepis_address} or a character vector of CEPs.}
+}
+\value{
+A character vector of masked CEPs. A value that is not 8 digits is
+returned unchanged, because this is a formatting helper and not a
+validator — \code{\link[=normalize_cep]{normalize_cep()}} is the validator.
+}
+\description{
+\code{"01001000"} becomes \code{"01001-000"}. The API always answers unmasked;
+formatting is presentation, and it lives here so it does not become a
+repeated \code{paste0()} in every project that uses this package.
+}
+\examples{
+formatted_cep("01001000")
+
+}
diff --git a/man/normalize_cep.Rd b/man/normalize_cep.Rd
new file mode 100644
index 0000000..6f9b462
--- /dev/null
+++ b/man/normalize_cep.Rd
@@ -0,0 +1,33 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/normalize.R
+\name{normalize_cep}
+\alias{normalize_cep}
+\title{Return the 8 digits of a CEP, accepting the mask}
+\usage{
+normalize_cep(value)
+}
+\arguments{
+\item{value}{A length-one character vector. Numbers are rejected on
+purpose: \code{1001000} has already lost the leading zero that makes
+\code{"01001000"} a CEP. Convert with \code{sprintf("\%08d", x)} first.}
+}
+\value{
+The 8 digits, as a length-one character vector.
+}
+\description{
+\code{"01001-000"}, \code{"01001000"}, \code{"01001.000"} and \code{" 01001-000 "} all become
+\code{"01001000"}.
+
+This runs \strong{before} any request: a 7-digit CEP is the caller's bug, and
+spending a round trip for the server to say so wastes both sides' time.
+}
+\section{Conditions}{
+
+Signals \link[=cepis_conditions]{cepis_invalid_cep} unless exactly 8 digits
+remain.
+}
+
+\examples{
+normalize_cep("01001-000")
+
+}