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 Plugin Laravel Package

saloonphp/laravel-plugin

Official Laravel integration for Saloon, the PHP HTTP client. Wire API integrations into Laravel with service provider and facade support, Laravel HTTP client sending, configuration, events, and testing helpers, making it easy to build and test robust API clients in your app.

View on GitHub
Deep Wiki
Context7

Getting Started

1. Install and confirm version pairing.

composer require saloonphp/laravel-plugin
composer show saloonphp/saloon saloonphp/laravel-plugin

The package is auto-discovered (SaloonServiceProvider + Saloon facade alias), so there is no manual registration. Check the installed majors: the plugin's major tracks Saloon's (v3 plugin → Saloon v3, v4 → v4, v5 → v5). Stubs, middleware classes, and mocking APIs differ between majors, so this is the first thing to verify before copying any snippet from a blog post.

2. Publish the config.

php artisan vendor:publish --tag=saloon

You get config/saloon.php. The setting you will actually touch is integrations_path (default app/Http/Integrations) — it drives where the generators write files and what namespace they emit.

3. Generate your first client. The plugin's real value is scaffolding; two commands get you from zero to a callable integration:

php artisan saloon:connector GitHub GitHubConnector
php artisan saloon:request  GitHub GetUserRequest

This produces app/Http/Integrations/GitHub/GitHubConnector.php and .../GitHub/Requests/GetUserRequest.php. Add --oauth to saloon:connector if the service needs an OAuth2 flow (it generates the authenticator wiring too).

4. Call it.

$response = GitHubConnector::make()->send(new GetUserRequest('sammyjo20'));
$user = $response->json();

Or inject the connector into a controller/job via the container — connectors are plain classes with a resolve() hook, so constructor injection works.

5. Orient yourself.

  • php artisan saloon:list — enumerates integrations and requests found on disk. This is your fastest way to understand an unfamiliar codebase.
  • docs.saloon.dev for the core concepts (connectors, requests, auth, retries, mocking). The plugin README is deliberately thin; almost everything you need is core Saloon documentation.
  • The repo's stubs/ directory and skills/saloon-development/SKILL.md (shipped for Laravel Boost) when you want to know exactly what a generated class will look like.
  • The changelog — this plugin's notable behaviour lives there, not in the docs.

Implementation Patterns

One connector per external service, requests grouped by resource. Keep GitHubConnector responsible for base URL, auth, headers, and default middleware; keep GetUserRequest responsible for the endpoint. Subdirectories (Requests/Users/, Requests/Repos/) are fine — the tooling and saloon:list scan recursively.

Configuration belongs in config/services.php, not in the connector.

class GitHubConnector extends Connector
{
    public function resolveBaseUrl(): string
    {
        return config('services.github.base_url', 'https://api.github.com');
    }

    protected function defaultAuth(): Authenticator
    {
        return new TokenAuthenticator(config('services.github.token'));
    }
}

This keeps config:cache working and makes test overrides trivial (config()->set(...) in setUp).

Testing is the highest-leverage habit. Use the global mock client (Saloon::fake()) rather than the older per-connector MockClient, which is deprecated in current majors:

use Saloon\Laravel\Facades\Saloon;

public function test_it_fetches_a_user(): void
{
    Saloon::fake([
        GetUserRequest::class => Saloon::response(['login' => 'sammyjo20'], 200),
    ]);

    (new SyncUserAction)->handle();

    Saloon::assertSent(GetUserRequest::class);
}

Keep fixtures in tests/Fixtures/ as JSON files and load them with MockResponse::fromFile() — it scales far better than inline arrays once responses grow.

Custom responses for typed data. php artisan saloon:response GitHub UserResponse generates a response class with createDtoFromResponse(). Use it whenever the raw JSON shape is nested or needs normalization; downstream code then depends on a DTO instead of $response->json('data.attributes').

Middleware for cross-cutting concerns. Correlation IDs, request logging, and tenant headers belong in middleware classes, not repeated in every request. The plugin also registers Laravel-aware middleware that bridges Saloon traffic into Laravel's event/observability stack.

Observability in non-production. The plugin ships Telescope and Pulse integrations. Enable them in local/staging — seeing the actual outbound request, headers, timing, and response inside Telescope cuts debugging time dramatically compared to Log::debug() around every call.

Queue long-running or fan-out calls. Wrap $connector->send() in a job rather than calling it in a web request; use sendAsync()/promises when you need to fan out to several endpoints and aggregate (e.g. dashboard widgets pulling from three services).

Retries and rate limits live on the request/connector, not in a for loop: use $request->retry(3, 1000) for transient 5xx/timeouts, and Saloon's rate-limit support (backed by Laravel's cache) when a vendor enforces quotas.

Gotchas and Tips

Version coupling is the number one source of confusion. Plugin v4 requires Saloon v4; v5 requires Saloon v5. If your connector extends a class whose signature changed, the error surfaces at runtime, not install time. Pin both explicitly in composer.json.

Custom integrations_path outside app/ was buggy until recently. PR #78 (v3.9.1) fixed namespace generation when the integrations directory lives outside app/. If you're on an earlier release and see classes generated with a broken namespace, that's why — upgrade rather than patching generated files by hand.

Mocking APIs have churned. MockClient was deprecated in favour of a reusable global mock client via Saloon::fake() (v3.3.0), then some deprecations were rolled back (v3.4.1). Pick one style, standardise it in a base TestCase, and don't mix Saloon::fake() with hand-constructed mock clients in the same suite — responses will not be intercepted the way you expect.

Telescope middleware can throw on non-object JSON bodies. A response with Content-Type: application/json but a body like 123 broke the Telescope middleware (fixed in v3.9.0); HAL+JSON rendering was fixed in v4.3.1. If Telescope errors only on certain endpoints, suspect the content-type/body mismatch first and upgrade before writing a workaround.

Don't register the Nightwatch middleware yourself. Double registration was fixed in v3.8.0; manually adding it again on a current version reintroduces duplicate entries.

Redact secrets before they hit Telescope or Pulse. v4.1.0 added sensitive-data handling. Audit your defaultHeaders()/auth setup and confirm tokens are marked sensitive — otherwise Authorization headers land in your observability database in plaintext.

Re-publish and re-read config/saloon.php after major upgrades. Config files published from an older major silently miss new keys.

saloon:list relies on filesystem scanning (Symfony Finder). Requests in unusual directories, or in packages outside your app path, may not be listed even though they work fine at runtime. Don't treat "not listed" as "not registered".

Extension points worth knowing: custom authenticators (saloon:auth), custom plugins (saloon:plugin) for shared headers/handlers across every connector, and the connector's defaultMiddleware()/middleware() methods for per-service and per-request behaviour respectively. Reach for a plugin when you're copying the same three middleware into a fifth connector.

The changelog is the real documentation. With ~79 stars and zero dependents in the index, community write-ups are scarce and often stale. For anything version-sensitive (mocking, middleware, path config), read the release notes in the repo before trusting a tutorial.

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.
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect
youbar/easy-crud
c-point-labs/laravel-hostyourai
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo