Weave Code
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

Saloon Laravel Package

saloonphp/saloon

Saloon is a Laravel/PHP-friendly HTTP client framework for building typed API connectors and requests. It supports middleware, authentication, retries, caching, testing/mocking, and async features, helping you create clean, reusable integrations without boilerplate.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation

    composer require saloonphp/saloon saloonphp/saloon-laravel
    

    Publish the Laravel config (if needed):

    php artisan vendor:publish --provider="Saloon\Laravel\SaloonServiceProvider"
    
  2. First Use Case: Fetching Data from an API Define a Connector (e.g., app/Connectors/StripeConnector.php):

    use Saloon\Connector;
    use Saloon\Traits\PlaysConnectors;
    
    class StripeConnector extends Connector
    {
        use PlaysConnectors;
    
        protected string $baseUrl = 'https://api.stripe.com/v1';
        protected string $defaultAuth = 'api_key';
        protected string $defaultAuthKey = 'sk_test_...';
    }
    

    Define a Request (e.g., app/Requests/GetCustomerRequest.php):

    use Saloon\Request;
    use Saloon\Traits\PlaysRequests;
    
    class GetCustomerRequest extends Request
    {
        use PlaysRequests;
    
        protected string $endpoint = 'customers/{customer_id}';
        protected string $method = 'GET';
        protected ?string $customer_id;
    }
    

    Send the request in a Laravel controller or service:

    $connector = resolve(StripeConnector::class);
    $response = $connector->send(new GetCustomerRequest(['customer_id' => 'cus_123']));
    $customer = $response->json();
    
  3. Where to Look First


Implementation Patterns

1. Connector Workflows

  • Base URL Overrides: Use withBaseUrl() or override in config:
    $connector->withBaseUrl('https://staging-api.stripe.com/v1');
    
  • Dynamic Auth: Swap authenticators dynamically:
    $connector->withAuth('oauth', ['token' => '...']);
    
  • Middleware: Attach global middleware (e.g., logging, retries):
    $connector->withMiddleware(new \Saloon\Http\Middleware\JsonResponse());
    

2. Request Patterns

  • Dynamic Endpoints: Use placeholders ({id}) and bind them:
    $request = new GetCustomerRequest(['customer_id' => 'cus_123']);
    
  • Query Parameters: Define in $query property or use withQuery():
    protected array $query = ['limit' => 10];
    
  • Headers: Set defaults or override per request:
    protected array $headers = ['Accept' => 'application/json'];
    
  • DTO Responses: Use resolve() to cast responses to objects:
    $response->resolve(CustomerDto::class);
    

3. Testing with Mocks

  • Mock Responses: Define fixtures in tests/Fixtures/:
    // tests/Fixtures/GetCustomerRequest.json
    {"id": "cus_123", "name": "John Doe"}
    
  • Assertions: Verify requests were sent correctly:
    $connector->assertSent(GetCustomerRequest::class, function ($request) {
        return $request->customer_id === 'cus_123';
    });
    
  • Global Mocking: Use MockClient for testing:
    $mock = new MockClient();
    $mock->shouldReceive('send')
        ->once()
        ->andReturn(new Response($fixture));
    

4. Laravel-Specific Patterns

  • Service Container Binding: Register connectors in AppServiceProvider:
    $this->app->bind(StripeConnector::class, function ($app) {
        return new StripeConnector();
    });
    
  • Cached Responses: Leverage Laravel’s cache for API responses:
    $response = $connector->send($request, ['cache' => true, 'cache_key' => 'stripe_customer_123']);
    
  • Events: Dispatch events for API responses:
    $connector->withMiddleware(new \Saloon\Http\Middleware\EventMiddleware([
        'Saloon\Events\RequestSent',
        'Saloon\Events\ResponseReceived',
    ]));
    

5. Advanced Patterns

  • Pagination: Use Saloon\Pagination\CursorPagination or OffsetPagination.
  • Retries: Configure exponential backoff:
    $connector->withMiddleware(new \Saloon\Http\Middleware\RetryMiddleware());
    
  • Plugins: Extend functionality with plugins (e.g., rate limiting):
    $connector->withPlugin(new \Saloon\Plugins\RateLimitPlugin());
    

Gotchas and Tips

Pitfalls

  1. Authentication Issues:

    • Gotcha: Forgetting to set defaultAuthKey or defaultAuth in the connector.
    • Fix: Ensure protected string $defaultAuth = 'api_key'; and protected string $defaultAuthKey = '...'; are set.
    • Debug: Use $connector->debug() to inspect the request payload.
  2. Endpoint URL Construction:

    • Gotcha: Underscores in endpoints (e.g., users/{user_id}) may cause issues with URL encoding.
    • Fix: Use hyphens or ensure proper URL encoding in $endpoint.
  3. Response Handling:

    • Gotcha: Assuming json() will always work, even for non-JSON responses.
    • Fix: Check response type first:
      if ($response->isJson()) {
          $data = $response->json();
      } else {
          $data = $response->body();
      }
      
    • Tip: Use response() to get the raw Psr\Http\Message\ResponseInterface for custom handling.
  4. Mocking Quirks:

    • Gotcha: Fixture paths are case-sensitive and must match the request class name.
    • Fix: Ensure fixtures are named exactly like the request class (e.g., GetCustomerRequest.json).
    • Tip: Use context in fixtures for dynamic data:
      {"id": "{{ customer_id }}", "name": "John Doe"}
      
  5. Middleware Order:

    • Gotcha: Middleware runs in reverse order of attachment (last added runs first).
    • Fix: Attach middleware in the desired execution order:
      $connector->withMiddleware(new MiddlewareA());
      $connector->withMiddleware(new MiddlewareB()); // Runs before MiddlewareA
      
  6. Deprecated Methods:

    • Gotcha: Using deprecated methods like sendAndRetry() (v3.6.4+).
    • Fix: Use send() with retry middleware instead.
  7. CVE-2026-33942 (v4.0.0):

    • Gotcha: Insecure deserialization in AccessTokenAuthenticator.
    • Fix: Upgrade to v4.0.0+ and avoid custom object injection in auth tokens.
  8. Absolute URL Overrides (v4.0.0):

    • Gotcha: Endpoint overrides with absolute URLs can leak credentials (SSRF risk).
    • Fix: Use relative paths or enable base_url_overrides in config:
      'base_url_overrides' => true,
      

Debugging Tips

  1. Enable Debug Mode:
    $connector->debug(); // Logs request/response details
    
  2. Inspect Raw Request/Response:
    $request = $connector->getRequest($requestClass);
    dd($request->toPsr());
    
  3. Use dd() or dump():
    $response->dump(); // Pretty-prints response body
    
  4. Check Headers:
    $response->headers->all(); // Returns all headers as an array
    

Extension Points

  1. Custom Authenticators: Create a new authenticator class:
    use Saloon\Authenticators\Authenticator;
    
    class CustomAuthenticator extends Authenticator
    {
        public function authenticate
    
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.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
milesj/emojibase
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport