Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Geoip Laravel Package

reefki/laravel-geoip

A Laravel package for IP geolocation that resolves visitors' country, city, and coordinates from their IP address, with a clean API, caching, and support for multiple GeoIP drivers so you can localize content and personalize responses.

View on GitHub
Deep Wiki
Context7

Getting Started

This release is a compatibility-and-correctness drop, so the first job is confirming your constraint matrix still resolves before you write any new code.

  1. Check your PHP floor. Laravel 13 and symfony/http-foundation v8 both raise the minimum PHP version. If your app or package still runs on an older PHP, Composer will silently hold you on v2.0.x — pin explicitly ("vendor/package": "^2.1") if you intend to move.
  2. Run composer update --dry-run and read the symfony/http-foundation resolution line. v8 support means the package now allows ^6.4|^7|^8; if you have a transitive constraint holding http-foundation at 7.x you'll stay there, which is fine — but you want to know which branch you're on before debugging.
  3. Look first at your retry callbacks. They are the only behavioural change in this release. Grep for retry( and any closure or class that handles a failed HTTP attempt.

Your first real use case is the one this release unblocks: retrying a flaky third-party API where the failure surfaces as something other than an Exception — a TypeError from a malformed payload, an Error from a typed DTO hydration step, or a connection-level throwable from the underlying client that doesn't extend Exception.

use Illuminate\Http\Client\ConnectionException;

$response = Http::retry(3, 200, function (Throwable $e) {
    return $e instanceof ConnectionException
        || $e instanceof TypeError;
})->post('https://api.example.com/orders', $payload);

Implementation Patterns

Type the callback as Throwable, not Exception. The closure signature is now wide enough to receive any throwable. If you write function (Exception $e) you are narrowing the parameter and will get a TypeError at call time when the package hands you an Error. Always declare Throwable in the closure.

Whitelist, don't blanket-retry. The value of the fix is that you can see non-Exception throwables — not that you should retry them. Assert on the specific failure modes you consider transient:

Http::retry(3, fn (int $attempt) => $attempt * 250, function (Throwable $e) {
    return $e instanceof ConnectionException          // DNS, TLS, timeout
        || ($e instanceof RequestException && $e->response?->serverError());
})->withHeaders(['Idempotency-Key' => $key])->post($url, $payload);

Keep retry policy in one place. Extract the decision into a small invokable class so the same policy applies across every client you own, and so you can unit-test it without hitting the network:

final class TransientFailure
{
    public function __invoke(Throwable $e): bool
    {
        return $e instanceof ConnectionException
            || ($e instanceof RequestException && $e->response->serverError());
    }
}

Http::retry(3, 200, new TransientFailure())->get($url);

Test the retry path with Http::fake() sequences. You can assert both the number of attempts and the final outcome, which is the cheapest way to prove the widened callback actually fires for the failure mode you care about:

Http::fake([
    'api.example.com/*' => Http::sequence()
        ->pushStatus(503)
        ->pushStatus(503)
        ->push(['ok' => true], 200),
]);

Http::retry(3, 0, new TransientFailure())->post('https://api.example.com/orders')
    ->assertOk();

Http::assertSentCount(3);

Mirror the Testbench matrix in CI. With orchestra/testbench at ^8.0|^9.0|^10.0|^11.0 you can run your own suite against every supported Laravel line from one matrix. Add the lowest and highest supported combos as required checks and let the middle ones be informational — that keeps PR feedback fast while still catching a Laravel 13-only break.

Plan your Laravel 13 upgrade as a separate PR. Nothing in this release forces you onto 13; treat it as an opt-in. Bump laravel/framework, PHP, and http-foundation together, then re-run the retry assertions — those are the only codepaths whose behaviour changed.

Gotchas and Tips

  • Contravariance will bite you if you implemented an interface. Widening a parameter type from Exception to Throwable is safe for closures, but if you have a class implementing a retry-related contract, PHP enforces the signature. An implementation declaring Exception where the contract now says Throwable is a fatal "Declaration must be compatible" — not a deprecation. Grep for Exception $e in anything that implements a package interface before upgrading.
  • A widened callback can mask real bugs. Error and TypeError almost always mean your code is wrong, not the network. Retrying them burns three attempts and a backoff sleep before surfacing the same defect, and it may hide the stack trace behind a retry-exhausted exception. Log the throwable class on every attempt so a sudden flood of TypeError retries is visible.
  • Retry only idempotent requests. Non-Exception throwables are more likely to arrive after the request was dispatched. A POST without an idempotency key that gets retried on a TypeError raised in your own response handling can double-charge a customer.
  • $sleep units and closures. Verify whether your version takes milliseconds or a closure receiving the attempt number — it differs across Laravel lines, and a wrong unit turns a 200 ms backoff into 200 seconds in staging.
  • Don't chase http-foundation v8 for its own sake. Symfony 8 support means "allowed", not "required". Staying on 7.x with Laravel 12 is a supported, boring configuration; upgrade when your framework upgrade forces it.
  • Composer resolution is the usual failure point, not the code. If composer update refuses, run composer why-not symfony/http-foundation 8 — the blocker is nearly always another package with a hard ^7 constraint, and knowing which one saves an afternoon.
  • Extension point: if your retry policy needs state (a circuit breaker, a per-tenant attempt budget), an invokable class is the seam to use — it can take constructor dependencies, which a closure registered at boot cannot do cleanly.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator