From 3069d341ae3fa177cbb3f2ef6d2b9e9ec8d0dccf Mon Sep 17 00:00:00 2001 From: Joel Wurtz Date: Sat, 31 Oct 2015 18:21:27 +0100 Subject: [PATCH 1/4] Add document for async client --- docs/discovery.md | 32 +++++++++++-- docs/httplug.md | 38 +++++++++++----- docs/tutorial.md | 113 ++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 164 insertions(+), 19 deletions(-) diff --git a/docs/discovery.md b/docs/discovery.md index 0169447..45b6555 100644 --- a/docs/discovery.md +++ b/docs/discovery.md @@ -19,7 +19,7 @@ composer require "php-http/discovery" ## HTTP Client Discovery -This type of discovery finds installed HTTP Clients. +This type of discovery finds a HTTPClient implementation. ``` php use Http\Client\HttpClient; @@ -42,10 +42,34 @@ class MyClass } ``` +## HTTP Async Client Discovery + +This type of discovery finds a HttpAsyncClient implementation. + +``` php +use Http\Client\HttpAsyncClient; +use Http\Discovery\HttpAsyncClientDiscovery; + +class MyClass +{ + /** + * @var HttpAsyncClient + */ + protected $httpAsyncClient; + + /** + * @param HttpAsyncClient|null $httpAsyncClient to do HTTP requests. + */ + public function __construct(HttpAsyncClient $httpAsyncClient = null) + { + $this->httpAsyncClient = $httpAsyncClient ?: HttpAsyncClientDiscovery::find(); + } +} +``` ## PSR-7 Message Factory Discovery -This type of discovery finds installed [PSR-7](http://www.php-fig.org/psr/psr-7/) Message implementations and their [factories](message-factory.md). +This type of discovery finds a [PSR-7](http://www.php-fig.org/psr/psr-7/) Message implementation and their [factories](message-factory.md). ``` php use Http\Message\MessageFactory; @@ -71,7 +95,7 @@ class MyClass ## PSR-7 URI Factory Discovery -This type of discovery finds installed [PSR-7](http://www.php-fig.org/psr/psr-7/) URI implementations and their factories. +This type of discovery finds a [PSR-7](http://www.php-fig.org/psr/psr-7/) URI implementation and their factories. ``` php use Http\Message\UriFactory; @@ -117,7 +141,7 @@ Classes registered manually are put on top of the list. ### Writing your own discovery -Each discovery service is based on the `ClassDiscovery` and has to specify a `cache` field and a `class` field to specify classes for the corresponding service. The fields need to be redeclared in each discovery class. If `ClassDiscovery` would declare them, they would be shared between the discovery classes which would make no sense. +Each discovery service is based on the `ClassDiscovery` and has to specify a `cache` field and a `class` field to specify classes for the corresponding service. The fields need to be redeclared in each discovery class. If `ClassDiscovery` would declare them, they would be shared between the discovery classes which would make no sense. Here is an example discovery: diff --git a/docs/httplug.md b/docs/httplug.md index a2a3242..038a3b5 100644 --- a/docs/httplug.md +++ b/docs/httplug.md @@ -5,22 +5,35 @@ Httplug is an abstraction for HTTP clients. There are two main use cases: 1. Usage in a project 2. Usage in a reusable package -In both cases, the client provides a `sendRequest` method to send a PSR-7 `RequestInterface` and returns a PSR-7 `ResponseInterface` or throws an exception that implements `Http\Client\Exception`. +In both cases, the client provides a `sendRequest` method to send a PSR-7 `RequestInterface` and returns a PSR-7 `ResponseInterface` +or throws an exception that implements `Http\Client\Exception`. -See the [tutorial](tutorial.md) for a concrete example. +There is also the HttpAsyncClient, available in [php-http/httplug-async](https://packagist.org/packages/php-http/httplug-async), which provides the `sendAsyncRequest` method to send a request asynchronously and returns a `Http\Client\Promise`. +It can be used later to retrieve a PSR-7 `ResponseInterface` or an exception that implements `Http\Client\Exception`. + +Contract for the HttpAsyncClient is still experimental and will be merged into Httplug repository once we considered it stable. +See the [tutorial](tutorial.md) for a concrete example. ## Httplug implementations -Httplug implementations typically are either HTTP clients of their own, or they are adapters wrapping existing clients like Guzzle 6. In the latter case, they will depend on the required client implementation, so you only need to require the adapter and not the actual client. +Httplug implementations typically are either HTTP clients of their own, or they are adapters wrapping existing clients like Guzzle 6. +In the latter case, they will depend on the required client implementation, so you only need to require the adapter and not the actual client. -See [packagist](https://packagist.org/providers/php-http/client-implementation) for the full list of implementations. +There is two kind of implementation: + + * [php-http/client-implementation](https://packagist.org/providers/php-http/client-implementation), the standard implementation, send requests with a synchronous workflow + * [php-http/client-async-implementation](https://packagist.org/providers/php-http/client-async-implementation), send requests with an asynchronous workflow by returning promises + +See [https://packagist.org/providers/php-http/client-implementation](https://packagist.org/providers/php-http/client-implementation) or [https://packagist.org/providers/php-http/client-async-implementation](https://packagist.org/providers/php-http/client-async-implementation) for +the full list of implementations. Note: Until Httplug 1.0 becomes stable, we will focus on the Guzzle6 adapter. ## Usage in a project -When writing an application, you need to require a concrete [client implementation](https://packagist.org/providers/php-http/client-implementation). +When writing an application, you need to require a concrete [client implementation](https://packagist.org/providers/php-http/client-implementation) or +a concrete [async client implementation](https://packagist.org/providers/php-http/client-async-implementation). See [virtual package](virtual-package.md) for more information on the topic of working with Httplug implementations. @@ -29,17 +42,20 @@ See [virtual package](virtual-package.md) for more information on the topic of w In many cases, packages are designed to be reused from the very beginning. For example, API clients are usually used in other packages/applications, not on their own. -In these cases, they should **not rely on a concrete implementation** (like Guzzle 6), but only require any implementation of Httplug. Httplug uses the concept of virtual packages. Instead of depending on only the interfaces, which would be missing an implementation, or depending on one concrete implementation, you should depend on the virtual package `php-http/client-implementation`. There is no package with that name, but all clients and adapters implementing Httplug declare that they provide this virtual package. +In these cases, they should **not rely on a concrete implementation** (like Guzzle 6), but only require any implementation of Httplug. +Httplug uses the concept of virtual packages. Instead of depending on only the interfaces, which would be missing an implementation, +or depending on one concrete implementation, you should depend on the virtual package `php-http/client-implementation` or `php-http/async-client-implementation`. +There is no package with that name, but all clients and adapters implementing Httplug declare that they provide one of this virtual package or both. You need to edit the `composer.json` of your package to add the virtual package. For development (installing the package standalone, running tests), add a concrete implementation in the `require-dev` section to make the project installable: ``` json ... -"require": { - "php-http/client-implementation": "^1.0" -}, -"require-dev": { - "php-http/guzzle6-adapter": "^1.0" +"require": { + "php-http/client-implementation": "^1.0" +}, +"require-dev": { + "php-http/guzzle6-adapter": "^1.0" }, ... ``` diff --git a/docs/tutorial.md b/docs/tutorial.md index e052dc5..320ea79 100644 --- a/docs/tutorial.md +++ b/docs/tutorial.md @@ -32,13 +32,118 @@ require('vendor/autoload.php'); TODO: create client instance with discovery and do some requests ``` -## Handling errors +## Using an asynchronous client -TODO: explain how to handle exceptions, distinction between network exception and HttpException. +When using an asynchronous client, it will use a PSR-7 `RequestInterface` and returns a `Http\Client\Promise` : + +```php +$httpAsyncClient = new HttpAsyncClientImplementation(); +$promise = $httpAsyncClient->sendAsyncRequest($request); +``` -## Doing parallel requests +This promise allows you to : + + * Add callbacks for when the response is available or an errors happens by using the then method: + + ```php + $promise->then(function (ResponseInterface $response) { + // onFulfilled callback + echo 'The response is available'; + + return $response; + }, function (Exception $e) { + // onRejected callback + echo 'An error happens'; + + throw $e; + }); + ``` + + This method will return another promise so you can manipulate the response and/or exception and + still provide a way to interact with this object for your users: + + ```php + $promise->then(function (ResponseInterface $response) { + // onFulfilled callback + echo 'The response is available'; + + return $response; + }, function (Exception $e) { + // onRejected callback + echo 'An error happens'; + + throw $e; + })->then(function (ResponseInterface $response) { + echo 'Response stil available'; + + return $response; + }, function (Exception $e) { + throw $e + }); + ``` + + In order to achieve the chain callback, if you read previous examples carefully, callbacks provided to the `then` method __must__ + return a PSR-7 `ResponseInterface` or throw a `Http\Client\Exception`. For both of the callbacks, if it returns a PSR-7 `ResponseInterface` + it will call the `onFulfilled` callback for the next element in the chain, if it throws a `Http\Client\Exception` it will call the `onRejected` + callback. + + i.e. you can inverse the behavior of a call: + + ```php + $promise->then(function (ResponseInterface $response) use($request) { + // onFulfilled callback + echo 'The response is available, but it\'s not ok...'; + + throw new HttpException('My error message', $request, $response); + }, function (Exception $e) { + // onRejected callback + echo 'An error happens, but it\'s ok...'; + + return $exception->getResponse(); + }); + ``` + + * Get the state of the promise with `$promise->getState()` will return of one `Promise::PENDING`, `Promise::FULFILLED` or `Promise::REJECTED` + * Get the response of the promise if it's in `FULFILLED` state with `$promise->getResponse()` call + * Get the error of the promise if it's in `REJECTED` state with `$promise->getRequest()` call + * wait for the callback to be fulfilled or rejected with the `$promise->wait()` call. The `wait` will return nothing, it will simply call one the callback + pass to the `then` method depending on the result of the call. It the promise has already been fulfilled or rejected it will do nothing. + +Here is a full example of a classic usage when using the `sendAsyncRequest` method: + +```php +$httpAsyncClient = new HttpAsyncClientImplementation(); + +$promise = $httpAsyncClient->sendAsyncRequest($request); +$promise->then(function (ResponseInterface $response) { + echo 'The response is available'; + + return $response; +}, function (Exception $e) { + echo 'An error happens'; + + throw $e; +}); + +// Do some stuff not depending on the response, calling another request, etc .. +... + +// We need now the response for our final treatment +$promise->wait(); + +if (Promise::FULFILLED === $promise->getState()) { + $response = $promise->getResponse(); +} else { + throw new \Exception('Response not available'); +} + +// Do your stuff with the response +... +``` + +## Handling errors -TODO explain sendRequests and how to work with BatchResult and BatchException +TODO: explain how to handle exceptions, distinction between network exception and HttpException. ## Writing a reusable package From af0befb50d10f2d61601e7039735e553fa2c3377 Mon Sep 17 00:00:00 2001 From: Joel Wurtz Date: Fri, 6 Nov 2015 14:24:42 +0100 Subject: [PATCH 2/4] Add a warning box, fix typo in library name --- docs/discovery.md | 4 ++-- docs/httplug.md | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/discovery.md b/docs/discovery.md index 45b6555..f86936b 100644 --- a/docs/discovery.md +++ b/docs/discovery.md @@ -19,7 +19,7 @@ composer require "php-http/discovery" ## HTTP Client Discovery -This type of discovery finds a HTTPClient implementation. +This type of discovery finds a HTTP Client implementation. ``` php use Http\Client\HttpClient; @@ -44,7 +44,7 @@ class MyClass ## HTTP Async Client Discovery -This type of discovery finds a HttpAsyncClient implementation. +This type of discovery finds a HTTP Async Client implementation. ``` php use Http\Client\HttpAsyncClient; diff --git a/docs/httplug.md b/docs/httplug.md index 038a3b5..df803b0 100644 --- a/docs/httplug.md +++ b/docs/httplug.md @@ -11,7 +11,11 @@ or throws an exception that implements `Http\Client\Exception`. There is also the HttpAsyncClient, available in [php-http/httplug-async](https://packagist.org/packages/php-http/httplug-async), which provides the `sendAsyncRequest` method to send a request asynchronously and returns a `Http\Client\Promise`. It can be used later to retrieve a PSR-7 `ResponseInterface` or an exception that implements `Http\Client\Exception`. -Contract for the HttpAsyncClient is still experimental and will be merged into Httplug repository once we considered it stable. + +

+ Contract for the HttpAsyncClient is experimental until [PSR about Promise is released](https://groups.google.com/forum/?fromgroups#!topic/php-fig/wzQWpLvNSjs). + Once it is out, we will use this interface in the main client and deprecate the separated repository. +

See the [tutorial](tutorial.md) for a concrete example. From 5c714c77c058c9568344c83cfeb95b4d9b869dee Mon Sep 17 00:00:00 2001 From: Joel Wurtz Date: Fri, 6 Nov 2015 22:20:51 +0100 Subject: [PATCH 3/4] Use discovery for tutorial --- docs/tutorial.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/tutorial.md b/docs/tutorial.md index 320ea79..ab8d974 100644 --- a/docs/tutorial.md +++ b/docs/tutorial.md @@ -37,7 +37,9 @@ TODO: create client instance with discovery and do some requests When using an asynchronous client, it will use a PSR-7 `RequestInterface` and returns a `Http\Client\Promise` : ```php -$httpAsyncClient = new HttpAsyncClientImplementation(); +use Http\Discovery\HttpAsyncClientDiscovery; + +$httpAsyncClient = HttpAsyncClientDiscovery::find(); $promise = $httpAsyncClient->sendAsyncRequest($request); ``` @@ -112,7 +114,9 @@ This promise allows you to : Here is a full example of a classic usage when using the `sendAsyncRequest` method: ```php -$httpAsyncClient = new HttpAsyncClientImplementation(); +use Http\Discovery\HttpAsyncClientDiscovery; + +$httpAsyncClient = HttpAsyncClientDiscovery::find(); $promise = $httpAsyncClient->sendAsyncRequest($request); $promise->then(function (ResponseInterface $response) { From 1ff4919400a1000e24591e8fc468d58ca32e4907 Mon Sep 17 00:00:00 2001 From: Joel Wurtz Date: Mon, 9 Nov 2015 00:42:23 +0100 Subject: [PATCH 4/4] Fix typo and rewrite tutorial part --- docs/discovery.md | 13 ++--- docs/httplug.md | 16 +++---- docs/tutorial.md | 119 ++++++++++++++++++++++++---------------------- 3 files changed, 76 insertions(+), 72 deletions(-) diff --git a/docs/discovery.md b/docs/discovery.md index f86936b..aee86fe 100644 --- a/docs/discovery.md +++ b/docs/discovery.md @@ -19,7 +19,7 @@ composer require "php-http/discovery" ## HTTP Client Discovery -This type of discovery finds a HTTP Client implementation. +This type of discovery finds an HTTP Client implementation. ``` php use Http\Client\HttpClient; @@ -33,7 +33,7 @@ class MyClass protected $httpClient; /** - * @param HttpClient|null $httpClient to do HTTP requests. + * @param HttpClient|null $httpClient Client to do HTTP requests, if not set, autodiscovery will be used to find a HTTP client. */ public function __construct(HttpClient $httpClient = null) { @@ -58,7 +58,7 @@ class MyClass protected $httpAsyncClient; /** - * @param HttpAsyncClient|null $httpAsyncClient to do HTTP requests. + * @param HttpAsyncClient|null $httpAsyncClient Client to do HTTP requests, if not set, autodiscovery will be used to find an asynchronous client. */ public function __construct(HttpAsyncClient $httpAsyncClient = null) { @@ -69,7 +69,7 @@ class MyClass ## PSR-7 Message Factory Discovery -This type of discovery finds a [PSR-7](http://www.php-fig.org/psr/psr-7/) Message implementation and their [factories](message-factory.md). +This type of discovery finds a [message factory](message-factory.md) for a [PSR-7](http://www.php-fig.org/psr/psr-7/) Message implementation. ``` php use Http\Message\MessageFactory; @@ -95,7 +95,7 @@ class MyClass ## PSR-7 URI Factory Discovery -This type of discovery finds a [PSR-7](http://www.php-fig.org/psr/psr-7/) URI implementation and their factories. +This type of discovery finds a uri factory for a [PSR-7](http://www.php-fig.org/psr/psr-7/) URI implementation. ``` php use Http\Message\UriFactory; @@ -141,7 +141,8 @@ Classes registered manually are put on top of the list. ### Writing your own discovery -Each discovery service is based on the `ClassDiscovery` and has to specify a `cache` field and a `class` field to specify classes for the corresponding service. The fields need to be redeclared in each discovery class. If `ClassDiscovery` would declare them, they would be shared between the discovery classes which would make no sense. +Each discovery service is based on the `ClassDiscovery` and has to specify a `cache` property and a `class` property to specify classes for the corresponding service. +Since they are static, this properties need to be redeclared in each discovery class. If `ClassDiscovery` would declare them, they would be shared between the discovery classes which would make no sense. Here is an example discovery: diff --git a/docs/httplug.md b/docs/httplug.md index df803b0..dfeb09a 100644 --- a/docs/httplug.md +++ b/docs/httplug.md @@ -5,10 +5,10 @@ Httplug is an abstraction for HTTP clients. There are two main use cases: 1. Usage in a project 2. Usage in a reusable package -In both cases, the client provides a `sendRequest` method to send a PSR-7 `RequestInterface` and returns a PSR-7 `ResponseInterface` +In both cases, the `Http\Client\HttpClient` provides a `sendRequest` method to send a PSR-7 `RequestInterface` and returns a PSR-7 `ResponseInterface` or throws an exception that implements `Http\Client\Exception`. -There is also the HttpAsyncClient, available in [php-http/httplug-async](https://packagist.org/packages/php-http/httplug-async), which provides the `sendAsyncRequest` method to send a request asynchronously and returns a `Http\Client\Promise`. +There is also the `Http\Client\HttpAsyncClient`, available in [php-http/httplug-async](https://packagist.org/packages/php-http/httplug-async), which provides the `sendAsyncRequest` method to send a request asynchronously and returns a `Http\Client\Promise`. It can be used later to retrieve a PSR-7 `ResponseInterface` or an exception that implements `Http\Client\Exception`. @@ -24,20 +24,18 @@ See the [tutorial](tutorial.md) for a concrete example. Httplug implementations typically are either HTTP clients of their own, or they are adapters wrapping existing clients like Guzzle 6. In the latter case, they will depend on the required client implementation, so you only need to require the adapter and not the actual client. -There is two kind of implementation: +There are two kind of implementation: - * [php-http/client-implementation](https://packagist.org/providers/php-http/client-implementation), the standard implementation, send requests with a synchronous workflow - * [php-http/client-async-implementation](https://packagist.org/providers/php-http/client-async-implementation), send requests with an asynchronous workflow by returning promises + - [php-http/client-implementation](https://packagist.org/providers/php-http/client-implementation), the synchronous implementation that waits for the response / error before returning from the `sendRequest` method. + - [php-http/client-async-implementation](https://packagist.org/providers/php-http/async-client-implementation), the asynchronous implementation that immediately returns a `Http\Client\Promise`, allowing to send several requests in parallel and handling responses later. -See [https://packagist.org/providers/php-http/client-implementation](https://packagist.org/providers/php-http/client-implementation) or [https://packagist.org/providers/php-http/client-async-implementation](https://packagist.org/providers/php-http/client-async-implementation) for -the full list of implementations. +Check links above for the full list of implementations. Note: Until Httplug 1.0 becomes stable, we will focus on the Guzzle6 adapter. ## Usage in a project -When writing an application, you need to require a concrete [client implementation](https://packagist.org/providers/php-http/client-implementation) or -a concrete [async client implementation](https://packagist.org/providers/php-http/client-async-implementation). +When writing an application, you need to require a concrete [implementation](https://packagist.org/providers/php-http/client-implementation). See [virtual package](virtual-package.md) for more information on the topic of working with Httplug implementations. diff --git a/docs/tutorial.md b/docs/tutorial.md index ab8d974..640ce68 100644 --- a/docs/tutorial.md +++ b/docs/tutorial.md @@ -34,7 +34,7 @@ TODO: create client instance with discovery and do some requests ## Using an asynchronous client -When using an asynchronous client, it will use a PSR-7 `RequestInterface` and returns a `Http\Client\Promise` : +Asynchronous client accepts a PSR-7 `RequestInterface` and returns a `Http\Client\Promise` : ```php use Http\Discovery\HttpAsyncClientDiscovery; @@ -43,73 +43,78 @@ $httpAsyncClient = HttpAsyncClientDiscovery::find(); $promise = $httpAsyncClient->sendAsyncRequest($request); ``` -This promise allows you to : +### Using callback system - * Add callbacks for when the response is available or an errors happens by using the then method: +This promise allows you to add callbacks for when the response is available or an errors happens by using the then method: - ```php - $promise->then(function (ResponseInterface $response) { - // onFulfilled callback - echo 'The response is available'; - - return $response; - }, function (Exception $e) { - // onRejected callback - echo 'An error happens'; - - throw $e; - }); - ``` +```php +$promise->then(function (ResponseInterface $response) { + // onFulfilled callback + echo 'The response is available'; + + return $response; +}, function (Exception $e) { + // onRejected callback + echo 'An error happens'; + + throw $e; +}); +``` - This method will return another promise so you can manipulate the response and/or exception and - still provide a way to interact with this object for your users: +This method will return another promise so you can manipulate the response and/or exception and +still provide a way to interact with this object for your users: - ```php - $promise->then(function (ResponseInterface $response) { - // onFulfilled callback - echo 'The response is available'; +```php +$promise->then(function (ResponseInterface $response) { + // onFulfilled callback + echo 'The response is available'; - return $response; - }, function (Exception $e) { - // onRejected callback - echo 'An error happens'; + return $response; +}, function (Exception $e) { + // onRejected callback + echo 'An error happens'; - throw $e; - })->then(function (ResponseInterface $response) { - echo 'Response stil available'; + throw $e; +})->then(function (ResponseInterface $response) { + echo 'Response stil available'; - return $response; - }, function (Exception $e) { - throw $e - }); - ``` + return $response; +}, function (Exception $e) { + throw $e +}); +``` - In order to achieve the chain callback, if you read previous examples carefully, callbacks provided to the `then` method __must__ - return a PSR-7 `ResponseInterface` or throw a `Http\Client\Exception`. For both of the callbacks, if it returns a PSR-7 `ResponseInterface` - it will call the `onFulfilled` callback for the next element in the chain, if it throws a `Http\Client\Exception` it will call the `onRejected` - callback. +In order to achieve the chain callback, if you read previous examples carefully, callbacks provided to the `then` method __must__ +return a PSR-7 `ResponseInterface` or throw a `Http\Client\Exception`. For both of the callbacks, if it returns a PSR-7 `ResponseInterface` +it will call the `onFulfilled` callback for the next element in the chain, if it throws a `Http\Client\Exception` it will call the `onRejected` +callback. - i.e. you can inverse the behavior of a call: +i.e. you can inverse the behavior of a call: - ```php - $promise->then(function (ResponseInterface $response) use($request) { - // onFulfilled callback - echo 'The response is available, but it\'s not ok...'; - - throw new HttpException('My error message', $request, $response); - }, function (Exception $e) { - // onRejected callback - echo 'An error happens, but it\'s ok...'; +```php +$promise->then(function (ResponseInterface $response) use($request) { + // onFulfilled callback + echo 'The response is available, but it\'s not ok...'; - return $exception->getResponse(); - }); - ``` - - * Get the state of the promise with `$promise->getState()` will return of one `Promise::PENDING`, `Promise::FULFILLED` or `Promise::REJECTED` - * Get the response of the promise if it's in `FULFILLED` state with `$promise->getResponse()` call - * Get the error of the promise if it's in `REJECTED` state with `$promise->getRequest()` call - * wait for the callback to be fulfilled or rejected with the `$promise->wait()` call. The `wait` will return nothing, it will simply call one the callback - pass to the `then` method depending on the result of the call. It the promise has already been fulfilled or rejected it will do nothing. + throw new HttpException('My error message', $request, $response); +}, function (Exception $e) { + // onRejected callback + echo 'An error happens, but it\'s ok...'; + + return $exception->getResponse(); +}); +``` + +Calling the `wait` method on the promise will wait for the response or exception to be available and invoke callback provided in the `then` method. + +### Using the promise directly + +If you don't want to use the callback system, you can also get the state of the promise with `$promise->getState()` will return of one `Promise::PENDING`, `Promise::FULFILLED` or `Promise::REJECTED` + +Then you can get the response of the promise if it's in `FULFILLED` state with `$promise->getResponse()` call or +get the error of the promise if it's in `REJECTED` state with `$promise->getRequest()` call + +### Example Here is a full example of a classic usage when using the `sendAsyncRequest` method: