saloonphp/laravel-plugin
Laravel plugin for Saloon that brings tight framework integration: service container bindings, config publishing, artisan tooling, and convenient HTTP client setup for building and managing API connectors and requests cleanly within Laravel apps.
Install the Package
composer require saloonphp/laravel-plugin
Publish the config (if needed):
php artisan vendor:publish --provider="Saloon\Laravel\SaloonServiceProvider"
Define Your First Connector Use the Artisan command to scaffold a connector:
php artisan saloon:connector StripeConnector
This generates:
app/Integrations/Stripe/StripeConnector.php (base connector)app/Integrations/Stripe/Requests/ (for request classes)app/Integrations/Stripe/Responses/ (for response classes)First Use Case: Make an API Request
use App\Integrations\Stripe\StripeConnector;
$connector = new StripeConnector();
$response = $connector->charge()->request([
'amount' => 1000,
'currency' => 'usd',
'source' => 'tok_visa',
]);
saloon:connector – Generate a new connector.saloon:request – Generate a request class.saloon:list – List all registered connectors.config/saloon.php (adjust integrations_path if needed).Saloon\Connector and define endpoints as methods.
class StripeConnector extends Connector
{
public function charge(): Request
{
return $this->request()
->withPath('/v1/charges')
->withMethod('post');
}
}
saloon:request to generate typed request classes.
php artisan saloon:request StripeChargeRequest --connector=StripeConnector
class StripeChargeRequest extends Request
{
public function resolveEndpoint(): string
{
return '/v1/charges';
}
public function resolveMethod(): string
{
return 'post';
}
public function resolveBody(): array
{
return [
'amount' => $this->amount,
'currency' => $this->currency,
'source' => $this->source,
];
}
}
resolveData() in response classes.
class StripeChargeResponse extends Response
{
public function resolveData(): array
{
return $this->data['data'];
}
}
$response = $connector->charge()->resolve();
$charge = $response->toModel(StripeCharge::class);
--oauth flag with saloon:connector.
php artisan saloon:connector GitHubConnector --oauth
$connector->withToken('Bearer ' . config('services.stripe.key'));
$this->app->singleton(StripeConnector::class, function ($app) {
return new StripeConnector();
});
$connector->charge()->then(function (StripeChargeResponse $response) {
event(new ChargeCreated($response->data()));
});
Saloon::fake() for contract testing.
public function test_charge_creation()
{
Saloon::fake([
StripeChargeRequest::class => [
'id' => 'ch_123',
'amount' => 1000,
],
]);
$response = $this->stripe->charge()->request([...]);
$this->assertEquals('ch_123', $response->id());
}
use Saloon\Testing\Nightwatch;
public function test_with_nightwatch()
{
Nightwatch::fake([
StripeChargeRequest::class => [...],
]);
// Test logic...
}
$connector->withMiddleware(new TelescopeMiddleware());
$connector->withMiddleware(new PulseMiddleware());
Integration Path Misconfiguration
integrations_path in config/saloon.php is incorrect, Artisan commands fail.app/ (e.g., app/Integrations).
'integrations_path' => app_path('Integrations'),
Middleware Registration Duplicates
Saloon::once() or check for existing middleware in boot().
if (! $this->app->bound('saloon.telescope')) {
$this->app->singleton('saloon.telescope', fn() => new TelescopeMiddleware());
}
Sensitive Data in Requests
public function resolveHeaders(): array
{
return [
'Authorization' => 'Bearer ' . config('services.stripe.key'),
];
}
PHP 8.5+ Deprecations
composer require saloonphp/saloon:^4.0
Contract Testing Gaps
Saloon::fake() with wildcards.
Saloon::fake([
StripeChargeRequest::class => [
'id' => 'ch_*',
'amount' => 1000,
],
]);
Enable Verbose Logging
Add to config/saloon.php:
'debug' => env('SALOON_DEBUG', false),
Then check logs for raw request/response payloads.
Inspect Raw Responses
Use dd($response->raw()) to debug unparsed responses.
Telescope Debugging
saloon.telescope middleware is registered.Nightwatch Assertions Verify mocks are applied:
Nightwatch::assertSent(StripeChargeRequest::class);
Custom Middleware
Extend Saloon\ConnectorMiddleware for reusable logic (e.g., rate limiting).
class RateLimitMiddleware extends ConnectorMiddleware
{
public function handle(Request $request, callable $next)
{
if ($request->getRateLimit() > 0) {
// Logic...
}
return $next($request);
}
}
Dynamic Connectors Use Laravel’s container to resolve connectors dynamically.
$connector = $this->app->make($request->connectorClass);
Contract Testing Extensions
Override Saloon::fake() behavior for custom assertions.
Saloon::extend(function ($connector) {
$connector->fakeCallback = fn($request) => [...];
});
IDE Support
Use the ide.json file for autocompletion in connectors/requests.
Example:
{
"namespaces": {
"App\\Integrations\\*\\*": "app/Integrations"
}
}
Reuse Connectors Bind connectors as singletons to avoid reinitializing clients.
$this->app->singleton(StripeConnector::class);
Lazy-Load Requests Use `->
How can I help you explore Laravel packages today?