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 Http Sender Laravel Package

saloonphp/laravel-http-sender

Laravel HTTP Sender for Saloon routes Saloon API requests through Laravel's HTTP client, letting you use Laravel's config, middleware, and testing helpers. A lightweight bridge that keeps Saloon requests native to your Laravel app.

View on GitHub
Deep Wiki
Context7

Getting Started

Install

composer require saloonphp/laravel-http-sender

This pulls in saloonphp/saloon (the framework-agnostic core) and registers the Laravel bridge via package auto-discovery — no manual providers entry in bootstrap/providers.php.

First five minutes

  1. Publish the config so you can see and adjust the defaults:
    php artisan vendor:publish --provider="Saloon\Laravel\SaloonServiceProvider"
    
  2. Confirm the generator commands are available (php artisan list | grep saloon) — they are the fastest way to scaffold a Connector/Request pair with the right base class and traits.
  3. Generate your first integration:
    php artisan saloon:connector AcmeApi
    php artisan saloon:request AcmeApi GetCustomerRequest
    
  4. Send it from a controller, service, or job by type-hinting the connector and letting the container resolve it:
    public function __invoke(AcmeApi $acme)
    {
        return $acme->send(new GetCustomerRequest($id))->json();
    }
    

First real use case: wrapping a single third-party API behind a Connector, then immediately writing a feature test with Saloon::fake(). That feedback loop — connector, request, fake, assert — is the whole package in miniature and covers 90% of day-to-day usage.

Where to look first: the published config/saloon.php (sender / default settings), the Saloon facade (faking, recording, assertions), and the base Connector/Request classes generated by the commands. Read those three things before reading any vendor source.

Upgrade note for v3.1.0: this release is additive — Laravel 12.x compatibility plus a PHP 8.4 implicit-nullable deprecation fix. No breaking changes, no config changes, no migration steps. If you are on Laravel 12 or PHP 8.4, pin ^3.1 rather than ^3.0.

Implementation Patterns

One Connector per external service, many Requests per Connector. Put baseUrl(), authentication, default headers, retry behaviour, and timeouts on the Connector; keep each Request focused on a single endpoint (method, path, body, query). This makes mocking coarse-grained (whole service) or fine-grained (single request) without touching call sites.

Let the container build your requests. Type-hinting AcmeApi in a controller, job, or listener means the sender is resolved from the Laravel container, which is what makes Saloon::fake() and any custom sender binding take effect. Manual new AcmeApi() inside a service provider's register() or in a config/*.php file bypasses container timing and is the most common reason fakes "don't work".

Authentication lives on the connector, not in callers. Use the generated auth classes (saloon:auth) for token-based flows; the connector's defaultAuth() then applies uniformly and refreshes are handled once instead of at every call site.

Testing is the primary workflow, not an afterthought. In feature tests:

Saloon::fake([
    GetCustomerRequest::class => MockResponse::make(['id' => 1, 'name' => 'Acme'], 200),
]);

// ... exercise the code under test ...

Saloon::assertSent(GetCustomerRequest::class);
Saloon::assertSent(function (GetCustomerRequest $request) {
    return str_contains($request->getUrl(), '/customers/1');
});

Use MockResponse::sequence([...]) for pagination/retry paths and assert on assertSentCount when a loop is supposed to batch rather than hammer.

Record once, replay forever. During initial integration work, record real responses into fixtures (typically under tests/Fixtures/Saloon/) and commit them. Convert to hand-written MockResponses only where you need deliberate edge cases (429s, malformed bodies, empty pages). Recorded fixtures keep test suites honest about real payload shapes; written mocks keep them honest about failure handling. You usually want both.

Isolate network calls behind a job. For anything user-facing and slow, dispatch a queued job that sends the request and maps the response into Eloquent/domain state. Keep Saloon's own retry middleware for transient 5xx/connection blips, and let queue retries handle broader failures — don't let the two multiply out to an accidental request storm.

Map responses into DTOs at the boundary. Either use a response class per request or map in a small service. Returning raw ->json() arrays deep into your app is how third-party schema changes become app-wide bugs.

Gotchas and Tips

  • Saloon::fake() and Http::fake() are not the same interception layer. Saloon fakes at the sender level; code that bypasses Saloon and calls Http:: directly will not be caught by Saloon::assertSent(), and vice versa. If a request escapes your fake and hits the network in CI, look for a stray Http:: call or a manually constructed connector first.
  • Fakes require container resolution. As above — new Connector() inside a factory method called before the app is booted, or cached singletons built in a service provider, can silently avoid the fake. Bind or type-hint; don't new.
  • Fixtures capture headers, including tokens. Recorded fixtures can contain Authorization values. Sanitise before committing, and never record against production credentials. This is the highest-severity routine mistake with this package.
  • Timeouts belong on the connector, not the caller. Set connect and request timeouts explicitly. A single connector with no timeout will pin queue workers indefinitely on a stalled upstream.
  • PHP 8.4 nullable parameters. v3.1.0 fixes the implicit-nullable deprecation inside the package, but your own middleware, custom senders, or subclasses with signatures like function handle(Foo $foo = null) will still emit deprecations. Write ?Foo $foo = null.
  • Laravel 12 support is in the bridge, not your plugins. If you also use Saloon's cache or rate-limit plugins, check those have compatible releases; a green composer update here doesn't guarantee the rest of the Saloon ecosystem is 12-ready.
  • Override the sender deliberately. If you need custom transport behaviour (tracing, tenant-scoped headers), bind a custom sender in a service provider rather than subclassing every connector — and make sure your test fakes still resolve through that binding.
  • Debugging a real call: log at the connector/request level with a short correlation id, and temporarily disable faking to capture a fresh fixture. The fastest diagnosis is almost always "what did the actual payload look like versus what I mocked".
  • Pin the minor. For Laravel 12 / PHP 8.4 use ^3.1; earlier 3.x predates both fixes and will surface deprecation noise or install conflicts that look like your bug but aren't.
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.
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
equipc/laravel-email-database-log
adedsec/nova-translated-labels
wazza/laravel-db-encryption
hokny/laravel-generator
vonsogt/backup
jengo/queues
jeremykenedy/laravel-observability
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums