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 PHP HTTP client framework for building clean, reusable API integrations. Create connectors and requests, handle auth, middleware and retries, mock and test easily, and keep endpoints organized with strong typing and a fluent DX.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require saloonphp/saloon
    

    For Laravel, add to config/app.php under providers:

    Saloon\Laravel\SaloonServiceProvider::class,
    
  2. First Request: Define a request class (e.g., GetUserRequest.php):

    namespace App\Saloon\Requests;
    
    use Saloon\Contracts\Request;
    use Saloon\Enums\HttpMethod;
    use Saloon\Traits\BodyTrait;
    use Saloon\Traits\HeadersTrait;
    
    class GetUserRequest implements Request
    {
        use BodyTrait, HeadersTrait;
    
        public function method(): string
        {
            return HttpMethod::GET;
        }
    
        public function endpoint(): string
        {
            return '/users/1';
        }
    }
    
  3. Send the Request:

    use App\Saloon\Requests\GetUserRequest;
    use Saloon\Http\Connector;
    
    $connector = new Connector();
    $response = $connector->send(new GetUserRequest());
    $user = $response->json();
    
  4. First Connector: Extend Connector for shared config (e.g., StripeConnector.php):

    namespace App\Saloon\Connectors;
    
    use Saloon\Http\Connector;
    use Saloon\Traits\BaseUrlTrait;
    
    class StripeConnector extends Connector
    {
        use BaseUrlTrait;
    
        protected string $baseUrl = 'https://api.stripe.com/v1';
        protected string $defaultAuth = 'BearerAuth'; // Auto-injects auth
    }
    

First Use Case: OAuth2 Integration

  1. Define Authenticator (e.g., OAuth2Authenticator.php):

    use Saloon\Contracts\Authenticator;
    use Saloon\Traits\Auth\OAuth2TokenTrait;
    
    class OAuth2Authenticator implements Authenticator
    {
        use OAuth2TokenTrait;
    
        public function authenticate(): array
        {
            return [
                'Authorization' => 'Bearer ' . $this->accessToken,
            ];
        }
    }
    
  2. Attach to Connector:

    class StripeConnector extends Connector
    {
        protected string $defaultAuth = OAuth2Authenticator::class;
        // ...
    }
    
  3. Send Authenticated Request:

    $connector->send(new GetUserRequest());
    

Where to Look First


Implementation Patterns

1. Connector-Driven Architecture

Pattern: Group related API endpoints under a single Connector class to centralize:

  • Base URLs
  • Default headers/auth
  • Middleware stacks
  • Error handling

Example:

class StripeConnector extends Connector
{
    use BaseUrlTrait, HeadersTrait;

    protected string $baseUrl = 'https://api.stripe.com/v1';
    protected string $defaultAuth = 'BearerAuth';

    public function resolveBaseUrl(): string
    {
        return config('services.stripe.url');
    }

    public function defaultHeaders(): array
    {
        return [
            'Idempotency-Key' => $this->generateIdempotencyKey(),
        ];
    }
}

Workflow:

  1. Define a connector for each API (e.g., StripeConnector, TwilioConnector).
  2. Inject the connector into services or use it directly:
    $stripe = app(StripeConnector::class);
    $response = $stripe->send(new CreateCustomerRequest());
    

2. Request-Level Customization

Pattern: Use request classes to override connector defaults per endpoint. Key Methods:

  • endpoint(): Override the URL.
  • method(): Change HTTP method (GET, POST, etc.).
  • headers()/body(): Add request-specific data.
  • auth(): Use a different authenticator.

Example:

class CreateChargeRequest extends Request
{
    use BodyTrait;

    public function method(): string
    {
        return HttpMethod::POST;
    }

    public function endpoint(): string
    {
        return '/charges';
    }

    public function body(): array
    {
        return [
            'amount' => $this->amount,
            'currency' => 'usd',
            'source' => $this->paymentMethodId,
        ];
    }

    public function auth(): string
    {
        return 'BearerAuth'; // Overrides connector default
    }
}

3. Middleware for Cross-Cutting Concerns

Pattern: Use middleware to handle retries, logging, or transformations. Common Middleware:

  • RetryMiddleware: Automatic retries for transient failures.
  • LoggingMiddleware: Log requests/responses.
  • TransformMiddleware: Convert responses to DTOs.

Example:

use Saloon\Contracts\Middleware;
use Saloon\Traits\Middleware\TransformsResponseTrait;

class TransformUserResponseMiddleware implements Middleware
{
    use TransformsResponseTrait;

    public function handle($request, callable $next)
    {
        $response = $next($request);

        return $this->transformResponse($response, UserDto::class);
    }
}

Attach to Connector:

class StripeConnector extends Connector
{
    protected array $middleware = [
        RetryMiddleware::class,
        LoggingMiddleware::class,
        TransformUserResponseMiddleware::class,
    ];
}

4. Authentication Strategies

Pattern: Centralize auth logic in authenticators. Supported Auth Types:

  • Bearer tokens (BearerAuth)
  • OAuth2 (OAuth2Authenticator)
  • Basic auth (BasicAuth)
  • API keys (ApiKeyAuth)

Example: OAuth2 Flow:

class OAuth2Authenticator implements Authenticator
{
    use OAuth2TokenTrait;

    public function authenticate(): array
    {
        $this->refreshTokenIfNeeded();
        return ['Authorization' => 'Bearer ' . $this->accessToken];
    }

    protected function refreshTokenIfNeeded(): void
    {
        if ($this->isTokenExpired()) {
            $this->refreshAccessToken();
        }
    }
}

Attach to Connector:

class GitHubConnector extends Connector
{
    protected string $defaultAuth = OAuth2Authenticator::class;
}

5. Testing with Mocks

Pattern: Use MockClient to simulate API responses in tests. Workflow:

  1. Define fixtures (JSON/XML files in tests/Fixtures).
  2. Mock the connector in tests.

Example:

use Saloon\Testing\MockClient;

beforeEach(function () {
    MockClient::shouldReceive('send')
        ->once()
        ->with(GetUserRequest::class)
        ->andReturnFromFixture('users/user_1.json');
});

it('fetches a user', function () {
    $user = $this->stripe->send(new GetUserRequest())->json();
    expect($user['id'])->toBe('user_123');
});

Fixture File (tests/Fixtures/users/user_1.json):

{
    "id": "user_123",
    "name": "John Doe"
}

6. Error Handling

Pattern: Use exceptions and middleware to handle errors gracefully. Key Classes:

  • SaloonException: Base exception.
  • ConnectionException: Network failures.
  • HttpException: HTTP errors (4xx/5xx).

Example:

use Saloon\Exceptions\HttpException;

try {
    $response = $connector->send(new GetUserRequest());
} catch (HttpException $e) {
    if ($e->response->status == 404) {
        // Handle not found
    }
    throw $e;
}

Custom Error Handling Middleware:

class HandleStripeErrorsMiddleware implements Middleware
{
    public function handle($request, callable $next)
    {
        try {
            return $next($request);
        } catch (HttpException $e) {
            if ($e->response->status == 400) {
                throw new \RuntimeException('Invalid Stripe request: ' . $e->response->json()['error']['message']);
            }
            throw $e;
        }
    }
}

7. Dynamic Requests

Pattern: Build requests dynamically using RequestBuilder. Use Case: Construct requests with runtime data (

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.
nexmo/api-specification
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
ecotone/kafka
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata