diff options
Diffstat (limited to 'src/Client.php')
| -rw-r--r-- | src/Client.php | 36 |
1 files changed, 32 insertions, 4 deletions
diff --git a/src/Client.php b/src/Client.php index 4e24b7f..5fd19b1 100644 --- a/src/Client.php +++ b/src/Client.php @@ -30,7 +30,7 @@ namespace Cepis; */ final class Client { - public const VERSION = '0.1.0'; + public const VERSION = '0.2.0'; /** * Where the API lives, unless `baseUrl` says otherwise. @@ -171,6 +171,12 @@ final class Client * the API's own message: the format already passed local validation, so * the server knows something this client does not. * + * A 404 is surfaced as {@see CepNotFoundException}, which may carry a + * {@see Faixa} naming the municipality the CEP would have belonged to. It + * is still a 404 either way: the `faixa` is context for the error, never an + * address, and a CEP that has one is just as absent from the DNE as one + * that does not. + * * @throws InvalidCepException the CEP is not 8 digits (no request is made). * @throws CepNotFoundException well-formed, but not in the database. * @throws RateLimitedException 429 after every attempt. @@ -184,9 +190,13 @@ final class Client [$status, $body] = $this->request('/' . $number); if ($status === 404) { - throw new CepNotFoundException( - sprintf('CEP %s does not exist in the DNE database', $number), - ); + $faixa = self::errorFaixa($body); + $message = sprintf('CEP %s does not exist in the DNE database', $number); + if ($faixa !== null) { + $message .= sprintf(' (the range covering it is %s)', $faixa->label()); + } + + throw new CepNotFoundException($message, $faixa); } if ($status === 400) { throw new InvalidCepException( @@ -390,6 +400,24 @@ final class Client } /** + * Pull the optional `faixa` block out of a 404 body, or `null`. + * + * Nothing in here throws, by design. The body of a not-found is extra + * information on top of an answer the caller already has, so a truncated + * response, an HTML error page from a proxy or a `faixa` in a shape this + * release does not know must all end the same way: no `faixa`, and the same + * {@see CepNotFoundException} that would have been thrown anyway. Note the + * plain `json_decode` — {@see Client::decodeJsonObject()} is deliberately + * not used here, because its whole job is to throw. + */ + private static function errorFaixa(string $body): ?Faixa + { + $data = json_decode($body, true); + + return is_array($data) ? Faixa::fromArray($data['faixa'] ?? null) : null; + } + + /** * Parse the `Retry-After` header in both RFC 9110 forms. * * It may arrive as a number of seconds (`"120"`) or as an HTTP date |