Making HTTP requests (e.g. to third-party APIs) is a frequent need for developers working on web applications. In Symfony 4.3 we'll make this simpler with a brand new component called HttpClient.
Basic usage
The Symfony\Component\HttpClient\HttpClient
class provided to make HTTP
requests is quite straightforward:
1 2 3 4
use Symfony\Component\HttpClient\HttpClient;
$httpClient = HttpClient::create();
$response = $httpClient->request('GET', 'https://api.github.com/repos/symfony/symfony-docs');
A significant difference with other existing HTTP clients is that the request()
call is not blocking. In other words, the $response
object is available
immediately and the code execution can continue.
Later, when you call to getStatusCode()
, the code execution will stop until
the headers are available and when you call to getContent()
, it will stop
until the full contents are available (but you can use Streaming responses):
1 2 3 4 5 6 7 8
$statusCode = $response->getStatusCode();
// $statusCode = 200
$content = $response->getContent();
// returns the raw content returned by the server (JSON in this case)
// $content = '{"id":521583, "name":"symfony-docs", ...}'
$content = $response->toArray();
// transforms the response JSON content into a PHP array
// $content = ['id' => 521583, 'name' => 'symfony-docs', ...]
Thanks to this non-blocking behavior, you can make multiple calls to
request()
to perform parallel requests and then access the info of the
responses only after starting all requests.
By default, the component uses native PHP functions to make the HTTP requests, so you don't have to install any other dependency. However, it will use the cURL based transport if your system has both the cURL library and the PHP cURL extension installed.
When the HTTP status code of the response is not in the 200-299 range (i.e.
3xx
, 4xx
or 5xx
) your code is expected to handle it. If you don't do
that, the getHeaders()
and getContent()
methods throw an appropriate
exception:
1 2 3 4 5 6 7 8 9 10 11 12 13
// the response of this request will be a 403 HTTP error
$response = $httpClient->request('GET', 'https://httpbin.org/status/403');
// this code results in a Symfony\Component\HttpClient\Exception\ClientException
// because it doesn't check the status code of the response
$content = $response->getContent();
// do this instead
if (200 !== $response->getStatusCode()) {
// handle the HTTP request error (e.g. retry the request)
} else {
$content = $response->getContent();
}
Features
The new HttpClient component is packed with useful features. All of them are explained in the docs:
- Support for HTTP Basic and HTTP Bearer authentications;
- Support for adding custom query string parameters and custom HTTP headers;
- Allow to upload data using strings, closures and PHP resources;
- Streaming responses to get chunks of the response sequentially instead of waiting for the entire response;
- Request and response caching;
- Scoping HTTP clients to auto-configure the client based on the requested URL;
- PSR-7 and PSR-18 Compatibility;
- MockHttpClient to simplify testing requests and responses.
Symfony framework integration
When using HttpClient inside a full Symfony application instead of as a
stand-alone component, you can configure it under the http_client
key
(check out the full HttpClient configuration reference):
1 2 3 4 5 6
# config/packages/framework.yaml
framework:
# ...
http_client:
max_redirects: 7
max_host_connections: 10
Then, you can inject the HttpClient in other services as follows:
1 2 3 4 5 6 7 8 9 10 11
use Symfony\Contracts\HttpClient\HttpClientInterface;
class SomeService
{
private $httpClient;
public function __construct(HttpClientInterface $httpClient)
{
$this->httpClient = $httpClient;
}
}
Future integrations
Having a default and official HTTP client for Symfony applications will allow us to implement other features that require communicating with third-party services. A recent example of this is the NotCompromisedPassword validator, which makes your applications more secure and uses the HttpClient component to make the HTTP requests required to check if a given password was publicly compromised or not.
In addition, the Mercure component is also switching their current HTTP client by the new HttpClient component (see PR #8). Finally, API Platform is going to introduce a new set of API testing utilities built with the HttpClient component (see PR #2608).
Hi ! Awesome feature !
What are the main differences with well known GuzzleHttp ?
Thanks
@Wait4Code the main difference in my opinion is a small hidden gem (not described in this blog post, but totally intended as part of the architecture of the component): the
request
method is non-blocking and returns a Response object immediately. Blocking calls are the accessors on the response (getStatusCode
andgetHeaders
block until headers are received, andgetContent
blocks until the content is available). This means that you can easily have multiple requests doing their IO concurrently: make multiple calls torequest
and then access the info of the responses only after starting all requests. That's one of the reasons why the component itself does not implement the PSR-18 interface (we provide a bridge to PSR, but you will loose that benefit as the bridge will need to block on IO before returning the PSR-7 response).@Christophe thanks for your comment. I've updated the blog post with more details.
That's very nice !
Thank you all for this work! You really make the PHP community better :)
Really good feature!
How do you "handle" status codes in 3xx-5xx range when you're expecting them, i.e. when you're actually going to use response body anyway? Is there an option disable http status check like
http_errors
(http://docs.guzzlephp.org/en/stable/request-options.html#http-errors)?Guzzle did have promise-based implementation for a long time, so it's not really that much different apart from the ability to stream the response in chunks in this regard.
Looking good though :)
Here are some slides I presented at SymfonyLive Paris & Tunis: https://speakerdeck.com/nicolasgrekas/symfony-httpclient-what-else
How are non-blocking responses in HttpClient different than using requestAsync and promises in Guzzle? With Guzzle, you have to "tickle" the curl connection to process data, which doesn't work well in applications that don't have an event loop. Does HttpClient solve this somehow?
I am excited to try this out on a project of mine
Magnificent ! I will implement it in my new features
Is there a way to use it instead of guzzle with flex?
I was looking for GuzzleHttpClient but then I found out about this new feature and I said let's give it a try. So far so good! Thumbs up!