Skip to content

Commit d2d63a2

Browse files
[Contracts] introduce HttpClient contracts
1 parent 1ad6f6f commit d2d63a2

14 files changed

+1245
-1
lines changed

src/Symfony/Contracts/CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
CHANGELOG
22
=========
33

4+
1.1.0
5+
-----
6+
7+
* added `HttpClient` namespace with contracts for implementing flexible HTTP clients
8+
49
1.0.0
510
-----
611

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Contracts\HttpClient;
13+
14+
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
15+
16+
/**
17+
* The interface of chunks returned by ResponseStreamInterface::current().
18+
*
19+
* When the chunk is first, last or timeout, the content MUST be empty.
20+
* When an unchecked timeout or a network error occurs, a TransportExceptionInterface
21+
* MUST be thrown by the destructor unless one was already thrown by another method.
22+
*
23+
* @author Nicolas Grekas <p@tchwork.com>
24+
*
25+
* @experimental in 1.1
26+
*/
27+
interface ChunkInterface
28+
{
29+
/**
30+
* Tells when the inactivity timeout has been reached.
31+
*
32+
* @throws TransportExceptionInterface on a network error
33+
*/
34+
public function isTimeout(): bool;
35+
36+
/**
37+
* Tells when headers just arrived.
38+
*
39+
* @throws TransportExceptionInterface on a network error or when the inactivity timeout is reached
40+
*/
41+
public function isFirst(): bool;
42+
43+
/**
44+
* Tells when the body just completed.
45+
*
46+
* @throws TransportExceptionInterface on a network error or when the inactivity timeout is reached
47+
*/
48+
public function isLast(): bool;
49+
50+
/**
51+
* Returns the content of the response chunk.
52+
*
53+
* @throws TransportExceptionInterface on a network error or when the inactivity timeout is reached
54+
*/
55+
public function getContent(): string;
56+
57+
/**
58+
* Returns the offset of the chunk in the response body.
59+
*/
60+
public function getOffset(): int;
61+
62+
/**
63+
* In case of error, returns the message that describes it.
64+
*/
65+
public function getError(): ?string;
66+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Contracts\HttpClient\Exception;
13+
14+
/**
15+
* When a 4xx response is returned.
16+
*
17+
* @author Nicolas Grekas <p@tchwork.com>
18+
*
19+
* @experimental in 1.1
20+
*/
21+
interface ClientExceptionInterface extends ExceptionInterface
22+
{
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Contracts\HttpClient\Exception;
13+
14+
/**
15+
* The base interface for all exceptions in the contract.
16+
*
17+
* @author Nicolas Grekas <p@tchwork.com>
18+
*
19+
* @experimental in 1.1
20+
*/
21+
interface ExceptionInterface extends \Throwable
22+
{
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Contracts\HttpClient\Exception;
13+
14+
/**
15+
* When a 3xx response is returned and the "max_redirects" option has been reached.
16+
*
17+
* @author Nicolas Grekas <p@tchwork.com>
18+
*
19+
* @experimental in 1.1
20+
*/
21+
interface RedirectionExceptionInterface extends ExceptionInterface
22+
{
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Contracts\HttpClient\Exception;
13+
14+
/**
15+
* When a 5xx response is returned.
16+
*
17+
* @author Nicolas Grekas <p@tchwork.com>
18+
*
19+
* @experimental in 1.1
20+
*/
21+
interface ServerExceptionInterface extends ExceptionInterface
22+
{
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Contracts\HttpClient\Exception;
13+
14+
/**
15+
* When any error happens at the transport level.
16+
*
17+
* @author Nicolas Grekas <p@tchwork.com>
18+
*
19+
* @experimental in 1.1
20+
*/
21+
interface TransportExceptionInterface extends ExceptionInterface
22+
{
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Contracts\HttpClient;
13+
14+
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
15+
use Symfony\Contracts\HttpClient\Test\HttpClientTestCase;
16+
17+
/**
18+
* Provides flexible methods for requesting HTTP resources synchronously or asynchronously.
19+
*
20+
* @see HttpClientTestCase for a reference test suite
21+
*
22+
* @author Nicolas Grekas <p@tchwork.com>
23+
*
24+
* @experimental in 1.1
25+
*/
26+
interface HttpClientInterface
27+
{
28+
public const OPTIONS_DEFAULTS = [
29+
'auth' => null, // string - a username:password enabling HTTP Basic authentication
30+
'query' => [], // string[] - associative array of query string values to merge with the request's URL
31+
'headers' => [], // iterable|string[]|string[][] - headers names provided as keys or as part of values
32+
'body' => '', // array|string|resource|\Traversable|\Closure - the callback SHOULD yield a string
33+
// smaller than the amount requested as argument; the empty string signals EOF; when
34+
// an array is passed, it is meant as a form payload of field names and values
35+
'json' => null, // array|\JsonSerializable - when set, implementations MUST set the "body" option to
36+
// the JSON-encoded value and set the "content-type" headers to a JSON-compatible
37+
// value it is they are not defined - typically "application/json"
38+
'user_data' => null, // mixed - any extra data to attach to the request (scalar, callable, object...) that
39+
// MUST be available via $response->getInfo('data') - not used internally
40+
'max_redirects' => 20, // int - the maximum number of redirects to follow; a value lower or equal to 0 means
41+
// redirects should not be followed; "Authorization" and "Cookie" headers MUST
42+
// NOT follow except for the initial host name
43+
'http_version' => null, // string - defaults to the best supported version, typically 1.1 or 2.0
44+
'base_uri' => null, // string - the URI to resolve relative URLs, following rules in RFC 3986, section 2
45+
'buffer' => true, // bool - whether the content of the response should be buffered or not
46+
'on_progress' => null, // callable(int $dlNow, int $dlSize, array $info) - throwing any exceptions MUST abort
47+
// the request; it MUST be called on DNS resolution, on arrival of headers and on
48+
// completion; it SHOULD be called on upload/download of data and at least 1/s
49+
'resolve' => [], // string[] - a map of host to IP address that SHOULD replace DNS resolution
50+
'proxy' => null, // string - by default, the proxy-related env vars handled by curl SHOULD be honored
51+
'no_proxy' => null, // string - a comma separated list of hosts that do not require a proxy to be reached
52+
'timeout' => null, // float - the inactivity timeout - defaults to ini_get('default_socket_timeout')
53+
'bindto' => '0', // string - the interface or the local socket to bind to
54+
'verify_peer' => true, // see https://php.net/context.ssl for the following options
55+
'verify_host' => true,
56+
'cafile' => null,
57+
'capath' => null,
58+
'local_cert' => null,
59+
'local_pk' => null,
60+
'passphrase' => null,
61+
'ciphers' => null,
62+
'peer_fingerprint' => null,
63+
'capture_peer_cert_chain' => false,
64+
];
65+
66+
/**
67+
* Requests an HTTP resource.
68+
*
69+
* Responses MUST be lazy, but their status code MUST be
70+
* checked even if none of their public methods are called.
71+
*
72+
* Implementations are not required to support all options described above; they can also
73+
* support more custom options; but in any case, they MUST throw a TransportExceptionInterface
74+
* when an unsupported option is passed.
75+
*
76+
* @throws TransportExceptionInterface When an unsupported option is passed
77+
*/
78+
public function request(string $method, string $url, array $options = []): ResponseInterface;
79+
80+
/**
81+
* Yields responses chunk by chunk as they complete.
82+
*
83+
* @param ResponseInterface|ResponseInterface[]|iterable $responses One or more responses created by the current HTTP client
84+
* @param float|null $timeout The inactivity timeout before exiting the iterator
85+
*/
86+
public function stream($responses, float $timeout = null): ResponseStreamInterface;
87+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Contracts\HttpClient;
13+
14+
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
15+
use Symfony\Contracts\HttpClient\Exception\ExceptionInterface;
16+
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
17+
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
18+
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
19+
20+
/**
21+
* A (lazily retrieved) HTTP response.
22+
*
23+
* @author Nicolas Grekas <p@tchwork.com>
24+
*
25+
* @experimental in 1.1
26+
*/
27+
interface ResponseInterface
28+
{
29+
/**
30+
* Gets the HTTP status code of the response.
31+
*
32+
* @throws TransportExceptionInterface when a network error occurs
33+
*/
34+
public function getStatusCode(): int;
35+
36+
/**
37+
* Gets the HTTP headers of the response.
38+
*
39+
* @param bool $throw Whether an exception should be thrown on 3/4/5xx status codes
40+
*
41+
* @return string[][] The headers of the response keyed by header names in lowercase
42+
*
43+
* @throws TransportExceptionInterface When a network error occurs
44+
* @throws RedirectionExceptionInterface On a 3xx when $throw is true and the "max_redirects" option has been reached
45+
* @throws ClientExceptionInterface On a 4xx when $throw is true
46+
* @throws ServerExceptionInterface On a 5xx when $throw is true
47+
*/
48+
public function getHeaders(bool $throw = true): array;
49+
50+
/**
51+
* Gets the response body as a string.
52+
*
53+
* @param bool $throw Whether an exception should be thrown on 3/4/5xx status codes
54+
*
55+
* @throws TransportExceptionInterface When a network error occurs
56+
* @throws RedirectionExceptionInterface On a 3xx when $throw is true and the "max_redirects" option has been reached
57+
* @throws ClientExceptionInterface On a 4xx when $throw is true
58+
* @throws ServerExceptionInterface On a 5xx when $throw is true
59+
*/
60+
public function getContent(bool $throw = true): string;
61+
62+
/**
63+
* Returns info coming from the transport layer.
64+
*
65+
* This method SHOULD NOT throw any ExceptionInterface and SHOULD be non-blocking.
66+
* The returned info is "live": it can be empty and can change from one call to
67+
* another, as the request/response progresses.
68+
*
69+
* The following info MUST be returned:
70+
* - raw_headers - an array modelled after the special $http_response_header variable
71+
* - redirect_count - the number of redirects followed while executing the request
72+
* - redirect_url - the resolved location of redirect responses, null otherwise
73+
* - start_time - the time when the request was sent or 0.0 when it's pending
74+
* - http_code - the last response code or 0 when it is not known yet
75+
* - error - the error message when the transfer was aborted, null otherwise
76+
* - data - the value of the "data" request option, null if not set
77+
* - url - the last effective URL of the request
78+
*
79+
* When the "capture_peer_cert_chain" option is true, the "peer_certificate_chain"
80+
* attribute SHOULD list the peer certificates as an array of OpenSSL X.509 resources.
81+
*
82+
* Other info SHOULD be named after curl_getinfo()'s associative return value.
83+
*
84+
* @return array|mixed|null An array of all available info, or one of them when $type is
85+
* provided, or null when an unsupported type is requested
86+
*/
87+
public function getInfo(string $type = null);
88+
}

0 commit comments

Comments
 (0)