Links
🌿

Upgrading from v1

This documentation is still a work in progress while Saloon v2 is in beta.

Introduction

It's time for the big upgrade to version two! There have been several major changes to Saloon in version two, so it's recommended that you read through what's new in v2 before starting the upgrade. You'll definitely need a cup of tea, coffee or beer if you fancy.

Estimated Upgrade Time

Simple integrations: 15-30 minutes
Advanced integrations and SDKs: ~30-45 minutes

Need help migrating from version one?

You can open a discussion on Saloon's Github page if you need any help with the migration process.

Installation

First, update Saloon in your composer.json file to use the version ^2.0. if you are using the additional Laravel package, you should update this to ^2.0 too. After that, run composer update.
Non-Laravel
Laravel
"require": {
"sammyjo20/saloon": "^2.0"
}
"require": {
"sammyjo20/saloon": "^2.0",
"sammyjo20/saloon-laravel": "^2.0"
}
If you previously used just "saloon-laravel" it's recommended that you add "sammyjo20/saloon" as an additional dependency to your require block.
Version two requires PHP 8.1 and Laravel 9 if you are using the additional Laravel helper package.

Namespace Changes

Estimated Impact: High
All of Saloon’s classes have a new namespace Saloon instead of Sammyjo20\Saloon. This change will affect every use of Saloon’s internal classes, so it’s recommended to run a find-and-replace.
  • Find: use Sammyjo20\Saloon
  • Replace: use Saloon

Laravel Namespace Changes

Estimated Impact: High
If you are using the Laravel helpers package for Saloon, you should also change the namespaces.
  • Find: use Sammyjo20\SaloonLaravel
  • Replace: use Saloon\Laravel

Class Name Changes

Estimated Impact: High
To help make Saloon more readable and to improve the developer experience, Saloon’s classes have changed names. There were a number of classes that had the name Saloon within, like SaloonRequest and SaloonConnector. you should find and replace these too. Please make sure that you have renamed the namespaces as instructed above first.

Connector

  • Find: use Saloon\Http\SaloonConnector
  • Replace: use Saloon\Http\Connector
  • Find: extends SaloonConnector
  • Replace: extends Connector

Request

  • Find: use Saloon\Http\SaloonRequest
  • Replace: use Saloon\Http\Request
  • Find: extends SaloonRequest
  • Replace: extends Request

MockClient

  • Find: use Saloon\Clients\MockClient
  • Replace: use Saloon\Http\Faking\MockClient

MockResponse

  • Find: use Saloon\Http\MockResponse
  • Replace: use Salooon\Http\Faking\MockResponse

Response (if using custom responses)

  • Find use Saloon\Http\SaloonResponse
  • Replace: use Saloon\Http\Response
  • Find: extends SaloonResponse
  • Replace: extends Response

Connector Changes

Estimated Impact: High
Saloon has also had a major refactor with the methods that are used to build and interact with connectors and requests. You should carefully find and replace the given strings.

Connector Methods

The connector’s base URL method has changed.
  • Find: public function defineBaseUrl(): string
  • Replace: public function resolveBaseUrl(): string
The method to define a custom response has changed.
  • Find: public function getResponseClass(): string
  • Replace: public function resolveResponseClass(): string
The request method has been removed.
The __call and __callStatic methods have been removed alongside the magic methods that build up requests. Including the requests property.

Request Changes

Estimated Impact: High

Request Methods

The request’s defineEndpoint method has changed.
  • Find: public function defineEndpoint(): string
  • Replace: public function resolveEndpoint(): string
The method to define a custom response has changed.
  • Find: public function getResponseClass(): string
  • Replace: public function resolveResponseClass(): string
The send, sendAsync, getConnector and setConnector methods and the connector property has been removed from the request. Please see below to add connector support back to your request if you need it
The getFullRequestUrl method has been removed from the request. You can get the URL of the request with the PendingRequest inside of the boot method, traits and middleware.
The __call method has been removed from the request. Any methods that no longer exist on the request will not be proxied to the connector.
The traitExistsOnConnector method has been removed from the request.

Request Properties

The request’s method property has changed to use a new Saloon\Enums\Method Enum. Make sure to migrate to use the new Enum too. For example: protected Method $method = Method::GET.
  • Find: protected ?string $method
  • Replace: protected Method $method

Updated way to send requests

Estimated Impact: High
With previous versions of Saloon, the recommended way to send requests was with the request and using the request send methods.
$request = new UserRequest;
$response = $request->send();
One of the points developers found frustrating was defining a connector class on every request that you make. This was solely so you could make a request directly without instantiating the connector.
This approach was very minimalist, but it introduced complexity and friction for the developer.
From version two, the connector property is being dropped entirely from the request. This means that you must send your requests through the connector like this:
$connector = new TwitterConnector;
$response = $connector->send(new UserRequest);
// or
TwitterConnector::make()->send(new UserRequest);
This allows you to have constructor arguments on the connector, perfect for API tokens or configuration. Similar to before, the request can have its own headers, config, query parameters and body but the connector will provide the very top-level defaults.
You should make sure that your requests use this new way of sending requests.

Using Request-First Sending

Although this is being taken out of the request, you may still add the functionality back with the HasConnector trait on the request. Although, if you add it back - you need to be aware of the downsides like not being able to have constructor arguments on your connector.

Updated Request, Headers, Query Parameters and Config Methods

Estimated Impact: High
Another notable change would be the simplification of interacting with headers, config and request body. Instead of individual methods for interacting with these properties, they are now wrapped in easy-to-understand methods with unified method names. Additionally, previously you wouldn't be able to access the default properties after instantiating the request, but now you can. You should make sure any references to headers, query parameters or config use the new methods.
Version 1
Version 2
<?php
$request = new GetForgeServerRequest(12345);
$request->addHeader($value);
$request->getHeader($value);
$request->setHeaders($value);
$request->mergeHeaders(...$values);
$request->getHeaders();
$request->addQuery($value);
$request->getQuery(?$value);
$request->setQuery($value);
$request->mergeQuery(...$values);
$request->addConfig($value);
$request->getConfig(?$value);
$request->setConfig($value);
$request->mergeConfig(...$values);
$request->addData($value);
$request->getData(?$value);
$request->setData($value);
$request->mergeData(...$values);
<?php
$request = new GetForgeServerRequest(12345);
$request->headers()->add($value);
$request->headers()->get($value, $default);
$request->headers()->set($value);
$request->headers()->merge(...$values);
$request->headers()->all();
$request->query()->add($value);
$request->query()->get($value, $default);
$request->query()->set($value);
$request->query()->merge(...$values);
$request->query()->all();
$request->config()->add($value);
$request->config()->get($value, $default);
$request->config()->set($value);
$request->config()->merge(...$values);
$request->config()->all();
// Data has been moved to body()... more on that below

Migrating to the new request body API

Estimated Impact: High
Saloon has also rebuilt the way that request data/body is sent using POST/PUT/PATCH requests. First, make sure that your data traits are using the new namespaces. It's recommended that you read through the new section on request body/data to understand why the changes have been made.
HasJsonBody
  • Find: use Saloon\Traits\Plugins\HasJsonBody
  • Replace: Saloon\Traits\Body\HasJsonBody
HasFormParams
  • Find: use Saloon\Traits\Plugins\HasFormParams
  • Replace: use Saloon\Traits\Body\HasFormBody
HasMultipartBody
  • Find: use Saloon\Traits\Plugins\HasMultipartBody
  • Replace: use Saloon\Traits\Body\HasMultipartBody
HasXMLBody
  • Find: use Saloon\Traits\Plugins\HasXMLBody
  • Replace: use Saloon\Traits\Body\HasXmlBody
  • Replace: use HasXMLBody
  • Find: use HasXmlBody
HasBody
  • Find: use Saloon\Traits\Plugins\HasBody
  • Replace: use Saloon\Traits\Body\HasBody
Next, add the HasBody interface to your request or connector. This interface is required for Saloon to properly detect if you are using request body or not. Since you have already added a body trait, the required body method should be implemented. You may need to re-index your IDE before it understands the changes made.

Syntax changed from data to body

Previously, Saloon called request body "data". To match PSR standards better, this has been renamed to "body".

Changing default

Previously, you may have defined a method like defaultData this needs to be renamed to defaultBody. The methods have also changed from being public to protected.
Version One
Version Two
<?php
class GetServersRequest extends Request
{
// {...}
public function defaultData(): array
{
return [
// ...
];
}
}
<?php
class GetServersRequest extends Request
{
// {...}
public function defaultBody(): array
{
return [
// ...
];
}
}
Make sure that you define the correct return type for your request body trait.

HasXMLBody defineXmlBody removed

Saloon has removed the defineXmlBody method when you use the HasXmlTrait. You must replace this with defaultBody

Request Body Methods

Saloon has also changed the previous request data methods. You should update your code accordingly if you used these old methods.
Version One
Version Two
<?php
$request = new CreateForgeSiteRequest($serverId, $domain);
$request->setData(['domain' => $customDomain]);
$request->mergeData(['database' => 'test123']);
$request->addData('name', 'my-saloon-server');
$request->getData('name');
<?php
$request = new CreateForgeSiteRequest($serverId, $domain);
$request->body()->set(['domain' => $customDomain]);
$request->body()->merge(['database' => 'test123']);
$request->body()->add('name', 'my-saloon-server');
$request->body()->get('name');

Removing Connector Magic Properties & Request Collections

Estimated Impact: High
With regards to request collections/request groups, Saloon has removed support for them entirely in v2. Previously, Saloon had a lot of "magic" logic which was cool, but tricky for IDEs to support. As request collections were just classes that passed in the connector, it's recommended that you create your own classes that support this, and then add methods into your connector.

Authentication

Estimated Impact: High
Saloon version two has removed the withAuth method. You should use the authenticate method instead.

Response Interceptors

Estimated Impact: High
Previously, Saloon had the concept of ResponseInterceptors which were functions that Saloon would call before returning the response back to the application. This API has been removed in favour of using the new Middleware API. It's recommended that you get yourself familiar with middleware, but here is an example of migrating from response interceptors to response middleware.
Version One
Version Two
<?php
$request->addResponseInterceptor(function (SaloonRequest $request, SaloonResponse $response) {
$response->throw();
return $response;
});
<?php
use Saloon\Contracts\Response;
$request->middleware()->onResponse(function (Response $response) {
$response->throw();
});

AlwaysThrowOnErrors Trait Rename

Estimated Impact: High
From Saloon version two, the AlwaysThrowsOnErrors trait has been renamed to AlwaysThrowOnErrors.
  • Find: Saloon\Traits\Plugins\AlwaysThrowsOnErrors
  • Replace: Saloon\Traits\Plugins\AlwaysThrowOnErrors
  • Find: use AlwaysThrowsOnErrors
  • Replace: use AlwaysThrowOnErrors

Boot Method Arguments

Estimated Impact: High
Saloon has a method that you can add on your connector and request to write logic while a request is being sent. This boot method has changed arguments in version two. It used to provide you with an instance of Request but will now provide you with an instance of PendingRequst. You should ensure any modifications are made on this PendingRequest instance and not use $this or modify the connector/request.
Version One
Version Two
<?php
class CreateForgeServerRequest extends SaloonRequest
{
// {...}
public function boot(SaloonRequest $request): void
{
$request->addHeader('X-Example', 'Hello');
}
}
<?php
use Saloon\Contracts\PendingRequest;
class CreateForgeServerRequest extends Request
{
// {...}
public function boot(PendingRequest $pendingRequest): void
{
$pendingRequest->headers()->add('X-Example', 'Hello');
}
}

Responses

Estimated Impact: Medium
Saloon’s Response class has changed to be a more generic, PSR-compatible response. If you are extending the existing Response class, you should make sure that it is still working correctly.

Plugin Traits

Estimated Impact: Medium
From version two, Saloon has updated its plugins. You can choose to add plugins to both your connector or your request. Previously, plugins would receive an instance of SaloonRequest in the arguments. Now, plugins will receive a PendingRequest instance. You should update your plugins accordingly.
You should also make any changes to the PendingRequest instance and not use $this as it's bad practice to overwrite the connector/request instance.

Guzzle Handlers/Middleware

Estimated Impact: Medium
Previously, Saloon allowed you to use the addHandler method to use a Guzzle middleware. From version two, Guzzle middleware is still supported with the default GuzzleSender, but you must migrate your handlers to the new API.
It's also recommended that you move any Guzzle middleware from requests into your connector class as middleware should only be executed once.
Version One
Version Two
<?php
class Forge extends SaloonConnector
{
//...
public function boot(SaloonRequest $request): void
{
$this->addHandler('customHeaderHandler', function (callable $handler) {
return function (RequestInterface $request, array $options) use ($handler) {
$request->withHeader('X-Custom-Header', 'Hello');
return $handler($request, $options);
};
});
}
}
<?php
class Forge extends Connector
{
//...
public function boot(PendingRequest $pendingRequest): void
{
$pendingRequest->sender()->addMiddleware(function (callable $handler) {
return function (RequestInterface $request, array $options) use ($handler) {
$request->withHeader('X-Custom-Header', 'Hello');
return $handler($request, $options);
};
}, 'customHandlerMiddleware');
}
}

Authenticator Traits

Estimated Impact: Low
Previously, Saloon had five traits which would throw an exception if a request or connector wasn’t authenticated. The following traits have now been removed:
  • RequiresBasicAuth
  • RequiresDigestAuth
  • RequiresTokenAuth
You should now use the generic RequiresAuth trait if you would still like to throw an exception.

OAuth Carbon Removal

Estimated Impact: Low
Saloon no longer has Carbon as a dependency, so all dates returned that used to return a CarbonInterface now return DateTimeImmutable
  • OAuthAuthenticator: getExpiresAt()
  • AccessTokenAuthenticator: getExpiresAt()

Mock Response From Request

Estimated Impact: Low
The MockResponse::fromRequest method has been removed from version two.