Hey everyone, thanks so much for all the support that you have given for Saloon. I can't believe it's almost at 500 stars on GitHub and receiving over 150 installs a day. I just wanted to take a moment to thank you all! 😀🙌
That being said, there are some good things coming to Saloon. I'm working on version 2, which will help create a road for the future of Saloon, as well as improving developer experience and making your life easier.
Here is a summary of the changes that are going to happen.
New Flow
Currently, Saloon will run your request through the "Request Manager" which merges all of the headers, config, and everything else from the connector and request into one. With Version 2, I am introducing the "PendingSaloonRequest". Inside of here, this is where all of the logic like merging properties together and running your plugins will happen. This is so the building of a request is entirely separate from the sending of requests. After that, it will be sent to the "Guzzle Sender", and the class will receive the full PendingSaloonRequest with all the final configuration and headers before sending.
I am changing to this new flow because eventually, I want Saloon to be HTTP client agnostic and allow you to use any client you like, so you don't have to use Guzzle if you don't want - and if Guzzle decides to be abandoned, Saloon won't be left in the dark.
Here's the new flow in detail.
The only exception to the flow in the image above is that it will not create a PSR-7 request just yet, I am still working that one out.
Other Changes
- Brand new middleware pipeline so you don't have to rely on Guzzle's handler pipeline
- Requests don’t go straight to the request manager anymore, they can be built within a PendingSaloonRequest.
- Better way to send data, by implementing interfaces that are processed by the PendingSaloonRequest.
- All properties of a request like headers, config, data, handlers etc. Will all be standardised and now in separate buckets like
$request→headers()→push()
.
- Interfaces to be used a lot more
- PHP 8.1 minimum
- Real asynchronous request
- Request pooling support
Middleware Pipeline
To help move the dependency on Guzzle, Saloon has also implanted its own middleware pipeline for requests and responses. This will replace the old Guzzle Handler support and response interceptors. You will be able to define request pipes and response pipes to modify the request/response before it is sent or given back to the user.
$request = new GetForgeServersRequest;
$request->middleware()
->addRequestPipe(function (PendingSaloonRequest $request) {
//
})
->addRequestPipe(new MyInvokableClass)
->addResponsePipe(function (SaloonResponse $response) {
//
})
Saloon's middleware pipeline will also be supported for asynchronous requests, so even if you have a pool of requests being sent simultaneously, they can each have their own middleware pipeline, which is something that Guzzle does not support with their existing handler stack logic, since you can only have one handler stack per client.
Middleware pipes can be added anywhere. Inside the request/connector, added by plugins, or even applied right before a request is sent. It will really allow you to tap into Saloon.
External API
Saloon’s external API will still remain the same, like the following:
<?php
$request = new GetForgeServersRequest;
$response = $request->send($mockClient);
$connnector = new ForgeConnector;
$request = $connector->request(new GetForgeServersRequest)->send();
$response = $request->send();
// Or
$connector->send($request);
There will be some additions to the external API, like interacting with request properties
<?php
// Before
$request = new GetForgeServersRequest;
$request->addHeader('X-User-Name', 'Sammy');
$request->addConfig('debug', true);
$config = $request->getConfig(); // Array
// Now
$request->headers()->push('X-User-Name', 'Sammy');
$request->config()->push('debug', true);
$config = $request->config()->all();
// Same with config, handlers, response interceptors, etc.
There will also be some new features, like the ability to set a mock client on the connector or a request, so it doesn’t have to be passed into the send of every request.
<?php
$request = new GetForgeServersRequest;
$request->withMockClient($mockClient);
$request->send(); // Won't need to set it here!
// Even more useful
$connector = new ForgeConnector;
$connector->withMockClient($mockClient);
// All requests using the connector will use the same mock client!
$connector->request($requestA)->send();
$connector->request($requestB)->send();