From 5e34a54d428e214df496a85ea9953cb0e10116c7 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 21 Aug 2019 19:04:53 +0200 Subject: [PATCH] [HttpClient] tell about ScopingHttpClient::forBaseUri() --- components/http_client.rst | 79 +++++++++++++++++++++++--------------- 1 file changed, 48 insertions(+), 31 deletions(-) diff --git a/components/http_client.rst b/components/http_client.rst index 226e7482916..f3ed12a74ef 100644 --- a/components/http_client.rst +++ b/components/http_client.rst @@ -31,8 +31,8 @@ low-level HTTP client that makes requests, like the following ``GET`` request:: use Symfony\Component\HttpClient\HttpClient; - $httpClient = HttpClient::create(); - $response = $httpClient->request('GET', 'https://api.github.com/repos/symfony/symfony-docs'); + $client = HttpClient::create(); + $response = $client->request('GET', 'https://api.github.com/repos/symfony/symfony-docs'); $statusCode = $response->getStatusCode(); // $statusCode = 200 @@ -68,10 +68,10 @@ the transport explicitly, use the following classes to create the client:: use Symfony\Component\HttpClient\NativeHttpClient; // uses native PHP streams - $httpClient = new NativeHttpClient(); + $client = new NativeHttpClient(); // uses the cURL PHP extension - $httpClient = new CurlHttpClient(); + $client = new CurlHttpClient(); When using this component in a full-stack Symfony application, this behavior is not configurable and cURL will be used automatically if the cURL PHP extension @@ -84,7 +84,7 @@ When requesting an ``https`` URL, HTTP/2 is enabled by default if libcurl >= 7.3 is used. To force HTTP/2 for ``http`` URLs, you need to enable it explicitly via the ``http_version`` option:: - $httpClient = HttpClient::create(['http_version' => '2.0']); + $client = HttpClient::create(['http_version' => '2.0']); Support for HTTP/2 PUSH works out of the box when libcurl >= 7.61 is used with PHP >= 7.2.17 / 7.3.4: pushed responses are put into a temporary cache and are @@ -96,16 +96,16 @@ Making Requests The client created with the ``HttpClient`` class provides a single ``request()`` method to perform all kinds of HTTP requests:: - $response = $httpClient->request('GET', 'https://...'); - $response = $httpClient->request('POST', 'https://...'); - $response = $httpClient->request('PUT', 'https://...'); + $response = $client->request('GET', 'https://...'); + $response = $client->request('POST', 'https://...'); + $response = $client->request('PUT', 'https://...'); // ... 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'); + $response = $client->request('GET', 'http://releases.ubuntu.com/18.04.2/ubuntu-18.04.2-desktop-amd64.iso'); // getting the response headers waits until they arrive $contentType = $response->getHeaders()['content-type'][0]; @@ -130,7 +130,7 @@ defined globally when creating the client (to apply it to all requests) and to each request (which overrides any global authentication):: // Use the same authentication for all requests - $httpClient = HttpClient::create([ + $client = HttpClient::create([ // HTTP Basic authentication with only the username and not a password 'auth_basic' => ['the-username'], @@ -141,7 +141,7 @@ each request (which overrides any global authentication):: 'auth_bearer' => 'the-bearer-token', ]); - $response = $httpClient->request('GET', 'https://...', [ + $response = $client->request('GET', 'https://...', [ // use a different HTTP Basic authentication only for this request 'auth_basic' => ['the-username', 'the-password'], @@ -155,7 +155,7 @@ 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', [ + $response = $client->request('GET', 'https://httpbin.org/get', [ // these values are automatically encoded before including them in the URL 'query' => [ 'token' => '...', @@ -170,13 +170,13 @@ Use the ``headers`` option to define both the default headers added to all requests and the specific headers for each request:: // this header is added to all requests made by this client - $httpClient = HttpClient::create(['headers' => [ + $client = HttpClient::create(['headers' => [ 'User-Agent' => 'My Fancy App', ]]); // this header is only included in this request and overrides the value // of the same header if defined globally by the HTTP client - $response = $httpClient->request('POST', 'https://...', [ + $response = $client->request('POST', 'https://...', [ 'headers' => [ 'Content-Type' => 'text/plain', ], @@ -189,7 +189,7 @@ This component provides several methods for uploading data using the ``body`` 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://...', [ + $response = $client->request('POST', 'https://...', [ // defining data using a regular string 'body' => 'raw data', @@ -222,7 +222,7 @@ A generator or any ``Traversable`` can also be used instead of a closure. given content will be JSON-encoded automatically and the request will add the ``Content-Type: application/json`` automatically too:: - $response = $httpClient->request('POST', 'https://...', [ + $response = $client->request('POST', 'https://...', [ 'json' => ['param1' => 'value1', '...'], ]); @@ -265,7 +265,7 @@ making a request. Use the ``max_redirects`` setting to configure this behavior (if the number of redirects is higher than the configured value, you'll get a :class:`Symfony\\Component\\HttpClient\\Exception\\RedirectionException`):: - $response = $httpClient->request('GET', 'https://...', [ + $response = $client->request('GET', 'https://...', [ // 0 means to not follow any redirect 'max_redirects' => 0, ]); @@ -294,7 +294,7 @@ uploads/downloads as they complete. This callback is guaranteed to be called on DNS resolution, on arrival of headers and on completion; additionally it is called when new data is uploaded or downloaded and at least once per second:: - $response = $httpClient->request('GET', 'https://...', [ + $response = $client->request('GET', 'https://...', [ 'on_progress' => function (int $dlNow, int $dlSize, array $info): void { // $dlNow is the number of bytes downloaded so far // $dlSize is the total size to be downloaded or -1 if it is unknown @@ -319,7 +319,7 @@ The response returned by all HTTP clients is an object of type :class:`Symfony\\Contracts\\HttpClient\\ResponseInterface` which provides the following methods:: - $response = $httpClient->request('GET', 'https://...'); + $response = $client->request('GET', 'https://...'); // gets the HTTP status code of the response $statusCode = $response->getStatusCode(); @@ -358,7 +358,7 @@ 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'; - $response = $httpClient->request('GET', $url, [ + $response = $client->request('GET', $url, [ // optional: if you don't want to buffer the response in memory 'buffer' => false, ]); @@ -371,7 +371,7 @@ response sequentially instead of waiting for the entire response:: // get the response contents in chunk and save them in a file // response chunks implement Symfony\Contracts\HttpClient\ChunkInterface $fileHandler = fopen('/ubuntu.iso', 'w'); - foreach ($httpClient->stream($response) as $chunk) { + foreach ($client->stream($response) as $chunk) { fwrite($fileHandler, $chunk->getContent()); } @@ -405,7 +405,7 @@ When the HTTP status code of the response is in the 300-599 range (i.e. 3xx, ``getHeaders()`` and ``getContent()`` methods throw an appropriate exception:: // the response of this request will be a 403 HTTP error - $response = $httpClient->request('GET', 'https://httpbin.org/status/403'); + $response = $client->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 @@ -600,8 +600,12 @@ class to autoconfigure the HTTP client based on the requested URL:: 'Authorization' => 'token '.$githubToken, ], ], + // ... ]); +You can define several scopes, so that each set of options is added only if a +requested URL matches one of the regular expressions provided as keys. + If the request URL is relative (because you use the ``base_uri`` option), the scoping HTTP client can't make a match. That's why you can define a third optional argument in its constructor which will be considered the default @@ -609,16 +613,29 @@ regular expression applied to relative URLs:: // ... - $httpClient = new ScopingHttpClient($client, [ - 'https://api\.github\.com/' => [ - 'base_uri' => 'https://api.github.com/', - // ... + $client = new ScopingHttpClient($client, + [ + 'https://api\.github\.com/' => [ + 'base_uri' => 'https://api.github.com/', + // ... + ], ], - ], - // this is the regexp applied to all relative URLs + // this is the index in the previous array that defines + // the base URI that shoud be used to resolve relative URLs 'https://api\.github\.com/' ); +The above example can be reduced to a simpler call:: + + // ... + + $client = ScopingHttpClient::forBaseUri($client, 'https://api.github.com/', [ + // ... + ]); + +This way, the provided options will be used only if the requested URL is relative +or if it matches the ``https://api.github.com/`` base URI. + Interoperability ---------------- @@ -744,11 +761,11 @@ into any services by type-hinting a constructor argument with the class SomeService { - private $httpClient; + private $client; - public function __construct(HttpClientInterface $httpClient) + public function __construct(HttpClientInterface $client) { - $this->httpClient = $httpClient; + $this->client = $client; } }