Skip to content

Improve doc for HttpClient #11586

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 29, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 38 additions & 42 deletions components/http_client.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,18 @@ The HttpClient Component
========================

The HttpClient component is a low-level HTTP client with support for both
PHP stream wrappers and cURL. It also provides utilities to consume APIs.
PHP stream wrappers and cURL. It provides utilities to consume APIs and
supports synchronous and asynchronous operations.

.. versionadded:: 4.3

The HttpClient component was introduced in Symfony 4.3.

.. TODO
.. tell about implementation vs abstraction
.. tell there are more options
.. tell chunked + compression are supported out of the box
Installation
------------

Expand Down Expand Up @@ -69,14 +75,15 @@ Enabling HTTP/2 Support
-----------------------

HTTP/2 is only supported when using the cURL-based transport and the libcurl
version is >= 7.36.0. If you meet these requirements, you can enable HTTP/2
explicitly via the ``http_version`` option::
version is >= 7.36.0. If you meet these requirements, HTTP/2 will be used by
default when the request protocol is ``https``. If you need it for ``http``,
you must enable it explicitly via the ``http_version`` option::

$httpClient = HttpClient::create(['http_version' => '2.0']);

If you don't set the HTTP version explicitly, Symfony will use ``'2.0'`` only
when the request protocol is ``https://`` (and the cURL requirements mentioned
earlier are met).
Support for HTTP/2 PUSH works out of the box when libcurl >= 7.61.0 is used with
PHP >= 7.2.17 / 7.3.4: pushed responses are put into a temporary cache and are
used when a subsequent request is triggered for the corresponding URLs.

Making Requests
---------------
Expand All @@ -89,14 +96,13 @@ method to perform all kinds of HTTP requests::
$response = $httpClient->request('PUT', 'https://...');
// ...

Responses are always asynchronous, so they are ready as soon as the response
HTTP headers are received, instead of waiting to receive the entire response
contents::
Responses are always asynchronous, so that the call to the method returns
immediately instead of waiting to receive the response::

// code execution continues immediately; it doesn't wait to receive the response
$response = $httpClient->request('GET', 'http://releases.ubuntu.com/18.04.2/ubuntu-18.04.2-desktop-amd64.iso');

// code execution continues immediately; it doesn't wait to receive the response
// you can get the value of any HTTP response header
// getting the response headers waits until they arrive
$contentType = $response->getHeaders()['content-type'][0];

// trying to get the response contents will block the execution until
Expand Down Expand Up @@ -135,8 +141,8 @@ each request (which overrides any global authentication)::
Query String Parameters
~~~~~~~~~~~~~~~~~~~~~~~

You can either append them manually to the requested URL, or better, add them
as an associative array to the ``query`` option::
You can either append them manually to the requested URL, or define them as an
associative array via the ``query`` option, that will be merged with the URL::

// it makes an HTTP GET request to https://httpbin.org/get?token=...&name=...
$response = $httpClient->request('GET', 'https://httpbin.org/get', [
Expand All @@ -155,7 +161,7 @@ requests and the specific headers for each request::

// this header is added to all requests made by this client
$httpClient = HttpClient::create(['headers' => [
'Accept-Encoding' => 'gzip',
'User-Agent' => 'My Fancy App',
]]);

// this header is only included in this request and overrides the value
Expand All @@ -170,7 +176,7 @@ Uploading Data
~~~~~~~~~~~~~~

This component provides several methods for uploading data using the ``body``
option. You can use regular strings, closures and resources and they'll be
option. You can use regular strings, closures, iterables and resources and they'll be
processed automatically when making the requests::

$response = $httpClient->request('POST', 'https://...', [
Expand Down Expand Up @@ -264,7 +270,7 @@ following methods::
Streaming Responses
~~~~~~~~~~~~~~~~~~~

Call to the ``stream()`` method of the HTTP client to get *chunks* of the
Call the ``stream()`` method of the HTTP client to get *chunks* of the
response sequentially instead of waiting for the entire response::

$url = 'https://releases.ubuntu.com/18.04.1/ubuntu-18.04.1-desktop-amd64.iso';
Expand All @@ -286,13 +292,13 @@ response sequentially instead of waiting for the entire response::
// response chunks implement Symfony\Contracts\HttpClient\ChunkInterface
$fileHandler = fopen('/ubuntu.iso', 'w');
foreach ($httpClient->stream($response) as $chunk) {
fwrite($fileHandler, $chunk->getContent(););
fwrite($fileHandler, $chunk->getContent());
}

Handling Exceptions
~~~~~~~~~~~~~~~~~~~

When the HTTP status code of the response is not in the 200-299 range (i.e. 3xx,
When the HTTP status code of the response is in the 300-599 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::

Expand Down Expand Up @@ -335,19 +341,15 @@ class to autoconfigure the HTTP client based on the requested URL::
use Symfony\Component\HttpClient\ScopingHttpClient;

$client = HttpClient::create();
$httpClient = new ScopingHttpClient($client, [
// the key is a regexp which must match the beginning of the request URL
$client = new ScopingHttpClient($client, [
// the options defined as values apply only to the URLs matching
// the regular expressions defined as keys
'https://api\.github\.com/' => [
'headers' => [
'Accept' => 'application/vnd.github.v3+json',
'Authorization' => 'token '.$githubToken,
],
],

// use a '*' wildcard to apply some options to all requests
'*' => [
// ...
]
]);

If the request URL is relative (because you use the ``base_uri`` option), the
Expand All @@ -362,30 +364,25 @@ regular expression applied to relative URLs::
'base_uri' => 'https://api.github.com/',
// ...
],

'*' => [
// ...
]
],
// this is the regexp applied to all relative URLs
'https://api\.github\.com/'
);

PSR-7 and PSR-18 Compatibility
------------------------------
PSR-18 Compatibility
--------------------

This component uses its own interfaces and exception classes different from the
ones defined in `PSR-7`_ (HTTP message interfaces) and `PSR-18`_ (HTTP Client).
However, it includes the :class:`Symfony\\Component\\HttpClient\\Psr18Client`
This component uses and implements abstractions defined by the
``symfony/contracts`` package. It also implements the `PSR-18`_ (HTTP Client)
specifications via the :class:`Symfony\\Component\\HttpClient\\Psr18Client`
class, which is an adapter to turn a Symfony ``HttpClientInterface`` into a
PSR-18 ``ClientInterface``.

Before using it in your application, run the following commands to install the
required dependencies:
To use it, you need the ``psr/http-client`` package and a `PSR-17`_ implementation:

.. code-block:: terminal
# installs the base ClientInterface
# installs the PSR-18 ClientInterface
$ composer require psr/http-client
# installs an efficient implementation of response and stream factories
Expand Down Expand Up @@ -437,12 +434,11 @@ If you want to define multiple HTTP clients, use this other expanded configurati
framework:
# ...
http_client:
http_clients:
crawler:
scoped_clients:
crawler.client:
headers: [{ 'X-Powered-By': 'ACME App' }]
http_version: '1.0'
default:
max_host_connections: 10
some_api.client:
max_redirects: 7
Injecting the HTTP Client Into Services
Expand Down Expand Up @@ -533,5 +529,5 @@ However, using ``MockResponse`` allows simulating chunked responses and timeouts
$mockResponse = new MockResponse($body());

.. _`cURL PHP extension`: https://php.net/curl
.. _`PSR-7`: https://www.php-fig.org/psr/psr-7/
.. _`PSR-17`: https://www.php-fig.org/psr/psr-17/
.. _`PSR-18`: https://www.php-fig.org/psr/psr-18/
138 changes: 81 additions & 57 deletions reference/configuration/framework.rst
Original file line number Diff line number Diff line change
Expand Up @@ -90,30 +90,51 @@ Configuration

* `http_client`_

* `auth_basic`_
* `auth_bearer`_
* `base_uri`_
* `bindto`_
* `buffer`_
* `cafile`_
* `capath`_
* `capture_peer_cert_chain`_
* `ciphers`_
* `headers`_
* `http_version`_
* `local_cert`_
* `local_pk`_
* `default_options`_

* `bindto`_
* `cafile`_
* `capath`_
* `ciphers`_
* `headers`_
* `http_version`_
* `local_cert`_
* `local_pk`_
* `max_redirects`_
* `no_proxy`_
* `passphrase`_
* `peer_fingerprint`_
* `proxy`_
* `resolve`_
* `timeout`_
* `verify_host`_
* `verify_peer`_

* `max_host_connections`_
* `max_redirects`_
* `no_proxy`_
* `passphrase`_
* `peer_fingerprint`_
* `proxy`_
* `query`_
* `resolve`_
* `timeout`_
* `verify_host`_
* `verify_peer`_
* `scoped_clients`_

* `scope`_
* `auth_basic`_
* `auth_bearer`_
* `base_uri`_
* `bindto`_
* `cafile`_
* `capath`_
* `ciphers`_
* `headers`_
* `http_version`_
* `local_cert`_
* `local_pk`_
* `max_redirects`_
* `no_proxy`_
* `passphrase`_
* `peer_fingerprint`_
* `proxy`_
* `query`_
* `resolve`_
* `timeout`_
* `verify_host`_
* `verify_peer`_

* `http_method_override`_
* `ide`_
Expand Down Expand Up @@ -662,39 +683,49 @@ when the request starts with this path.
http_client
~~~~~~~~~~~

If there's only one HTTP client defined in the app, you can configure it
directly under the ``framework.http_client`` option:
When the HttpClient component is installed, an HTTP client is available
as a service named ``http_client`` or using the autowiring alias
:class:`Symfony\\Constracts\\HttpClient\\HttpClientInterface`.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/Constracts/Contracts


This service can be configured using ``framework.http_client.default_options``:

.. code-block:: yaml

# config/packages/framework.yaml
framework:
# ...
http_client:
headers: [{ 'X-Powered-By': 'ACME App' }]
max_host_connections: 10
max_redirects: 7
default_options:
headers: [{ 'X-Powered-By': 'ACME App' }]
max_redirects: 7

If the app defines multiple HTTP clients, you must give them a unique name and
define them under the type of HTTP client you are creating (``http_clients`` for
regular clients and ``api_clients`` for clients that include utilities to
consume APIs):
Multiple pre-configured HTTP client services can be defined, each with its
service name defined as a key under ``scoped_clients``. Scoped clients inherit
the default options defined for the ``http_client`` service. You can override
these options and can define a few others:

.. code-block:: yaml

# config/packages/framework.yaml
framework:
# ...
http_client:
http_clients:
crawler:
# ...
default:
# ...
api_clients:
github:
scoped_clients:
my_api.client:
auth_bearer: secret_bearer_token
# ...

Options defined for scoped clients apply only to URLs that match either their
`base_uri`_ or the `scope`_ option when it is defined. Non-matching URLs always
use default options.

Each scoped client also define a corresponding named autowiring alias.
E.g. if you use
``Symfony\Constracts\HttpClient\HttpClientInterface $myApiClient``
as the type and name of an argument, autowiring will inject the ``my_api.client``
service into your autowired classes.

auth_basic
..........

Expand Down Expand Up @@ -743,15 +774,6 @@ bindto
A network interface name, IP address, a host name or a UNIX socket to use as the
outgoing network interface.

buffer
......

**type**: ``boolean``

.. TODO: improve this useless description

Indicates if the response should be buffered or not.

cafile
......

Expand All @@ -767,14 +789,6 @@ capath

The path to a directory that contains one or more certificate authority files.

capture_peer_cert_chain
.......................

**type**: ``boolean``

If ``true``, the response includes a ``peer_certificate_chain`` attribute with
the peer certificates (OpenSSL X.509 resources).

ciphers
.......

Expand Down Expand Up @@ -887,17 +901,27 @@ resolve

A list of hostnames and their IP addresses to pre-populate the DNS cache used by
the HTTP client in order to avoid a DNS lookup for those hosts. This option is
useful both to improve performance and to make your tests easier.
useful to improve security when IPs are checked before the URL is passed to the
client and to make your tests easier.

The value of this option is an associative array of ``domain => IP address``
(e.g ``['symfony.com' => '46.137.106.254', ...]``).

scope
.....

**type**: ``string``

For scoped clients only: the regular expression that the URL must match before
applying all other non-default options. By default, the scope is derived from
`base_uri`_.

timeout
.......

**type**: ``float`` **default**: depends on your PHP config

Time, in seconds, to wait for a response. If the response takes longer, a
Time, in seconds, to wait for a response. If the response stales for longer, a
:class:`Symfony\\Component\\HttpClient\\Exception\\TransportException` is thrown.
Its default value is the same as the value of PHP's `default_socket_timeout`_
config option.
Expand Down