saade/cep-php
PHP library for Brazilian CEP postal code lookups. Query a CEP and retrieve address details such as street, neighborhood, city, and state through a simple, lightweight API, making it easy to add postal code search to PHP applications.
Architecture fit
Cep::get(), Cep::race(), SomeProvider::get()) returning a CepResponse DTO, with provider-specific logic behind it.request() / handleErrors() / toDTO(), dispatched on Guzzle. Fewer moving parts, one fewer third-party abstraction, and the extension seam is now a plain subclass with typed hooks rather than a framework-specific request/connector pair.Provider::useClient() is the architecturally significant addition: it makes the transport injectable, which is what enables proxying, retry policy, and deterministic tests without a mocking framework.Integration feasibility
Cep::get(), Cep::race() or Provider::get(), the release notes state behavior, provider order, endpoints and timeouts are identical to v1.2.0.Technical risk
MockClient no longer intercepts. Any existing test relying on it will not fail loudly; it will attempt real network calls. This must be treated as a mandatory code-search item, not a nice-to-have.Saade\Cep\Requests\* and Saade\Cep\Connectors\RaceConnector are gone. Any direct reference is a fatal error at autoload/instantiation time.guzzlehttp/guzzle: ^7.15.2|^8.0.1 can force upgrades elsewhere. Older Guzzle releases carry published advisories, so this is intentional — but it can surface conflicts with packages pinning older Guzzle, and Guzzle 8 support across the rest of our stack needs verification.getAsync() / sendAsync() no longer accept a connector while still returning a Guzzle promise. Any wrapper code passing a connector breaks at call time.composer update elsewhere can remove it.Key questions
Saade\Cep\Requests\* / RaceConnector?MockClient anywhere against this package?race() fails — exception type, aggregation of errors?race() cancel losing in-flight requests, or do they complete and consume quota?Stack fit
guzzlehttp/guzzle ^7.15.2|^8.0.1, and the package's Laravel service provider/facade registration.Provider::useClient(), which fits cleanly behind our existing HTTP conventions (proxy egress, correlation IDs, retry policy).Migration path (v1.2.0 → v2.0.0)
grep for Cep::, Saade\Cep\, Requests\, RaceConnector, getAsync, sendAsync, MockClient.composer why guzzlehttp/guzzle and composer update guzzlehttp/guzzle on a branch, run the full suite. Isolating this step separates dependency-conflict failures from package-API failures.^2.0.request(): RequestInterface, handleErrors(ResponseInterface): void, toDTO(ResponseInterface): CepResponse. Note the release-note example uses a raw GuzzleHttp\Psr7\Request with manual JSON decoding via $this->json($response).MockClient to Provider::useClient() with a Guzzle MockHandler/HandlerStack. Add an assertion or CI guard that no real network egress occurs in unit tests.null between tests to avoid leaking a fake across the suite.Compatibility
^7.15.2 and accept the floor.Provider::useClient() is global/static in shape — if we inject a client, it affects every provider for the process. Account for that in long-running workers (Octane, queue workers) where state persists across requests.Sequencing
MockClient usage, this collapses to a same-day dependency bump plus a staging smoke test.Maintenance
Support
useClient() behavior.Scaling
Cep::race() fans out to multiple providers per lookup: outbound request volume and egress scale with provider count, and p95 latency is bounded by the slowest participating provider, not the fastest, unless losers are cancelled (unconfirmed).protected float $timeout = 5) compound under race and retry configurations; worst-case lookup latency needs to be computed, not assumed.getAsync()/sendAsync() with bounded concurrency, or push to a queue. Unbounded promise fan-out against public CEP APIs is a rate-limit incident waiting to happen.Failure modes
race() absorbs it only if at least one other provider is healthy. All-providers-down needs an explicit catch and a graceful degradation path (manual address entry) rather than a checkout-blocking exception.handleErrors() / toDTO() throwing or producing partial DTOs; validate that null fields (street, neighborhood) are tolerated downstream.Class not found at runtime, likely on a rarely exercised code path (custom provider, async wrapper) — hence the grep step.useClient() fake set in tests or a proxy client set in a bootstrapper persisting into worker requests.Ramp-up
get, race, per-provider get, CepResponse) — a Laravel developer is productive in well under a day.CepResponse.How can I help you explore Laravel packages today?