Skip to content

Commit 8fc9328

Browse files
committed
Merge pull request #13 from php-http/feature/http-client-router
Add http client router feature, closes #12
2 parents 473a690 + dacaf68 commit 8fc9328

File tree

4 files changed

+140
-1
lines changed

4 files changed

+140
-1
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
### Added
66

77
- Add a flexible http client providing both contract, and only emulating what's necessary
8+
- HTTP Client Router: route requests to underlying clients
89

910

1011
## 1.0.0 - 2016-01-27

composer.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
"require": {
1414
"php": ">=5.4",
1515
"php-http/httplug": "^1.0",
16-
"php-http/message-factory": "^1.0"
16+
"php-http/message-factory": "^1.0",
17+
"php-http/message": "^1.2"
1718
},
1819
"require-dev": {
1920
"phpspec/phpspec": "^2.4",

spec/HttpClientRouterSpec.php

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
<?php
2+
3+
namespace spec\Http\Client\Common;
4+
5+
use Http\Message\RequestMatcher;
6+
use Http\Client\HttpAsyncClient;
7+
use Http\Client\HttpClient;
8+
use Http\Promise\Promise;
9+
use Psr\Http\Message\RequestInterface;
10+
use Psr\Http\Message\ResponseInterface;
11+
use PhpSpec\ObjectBehavior;
12+
13+
class HttpClientRouterSpec extends ObjectBehavior
14+
{
15+
function it_is_initializable()
16+
{
17+
$this->shouldHaveType('Http\Client\Common\HttpClientRouter');
18+
}
19+
20+
function it_is_an_http_client()
21+
{
22+
$this->shouldImplement('Http\Client\HttpClient');
23+
}
24+
25+
function it_is_an_async_http_client()
26+
{
27+
$this->shouldImplement('Http\Client\HttpAsyncClient');
28+
}
29+
30+
function it_send_request(RequestMatcher $matcher, HttpClient $client, RequestInterface $request, ResponseInterface $response)
31+
{
32+
$this->addClient($client, $matcher);
33+
$matcher->matches($request)->willReturn(true);
34+
$client->sendRequest($request)->willReturn($response);
35+
36+
$this->sendRequest($request)->shouldReturn($response);
37+
}
38+
39+
function it_send_async_request(RequestMatcher $matcher, HttpAsyncClient $client, RequestInterface $request, Promise $promise)
40+
{
41+
$this->addClient($client, $matcher);
42+
$matcher->matches($request)->willReturn(true);
43+
$client->sendAsyncRequest($request)->willReturn($promise);
44+
45+
$this->sendAsyncRequest($request)->shouldReturn($promise);
46+
}
47+
48+
function it_throw_exception_on_send_request(RequestMatcher $matcher, HttpClient $client, RequestInterface $request)
49+
{
50+
$this->addClient($client, $matcher);
51+
$matcher->matches($request)->willReturn(false);
52+
53+
$this->shouldThrow('Http\Client\Exception\RequestException')->duringSendRequest($request);
54+
}
55+
56+
function it_throw_exception_on_send_async_request(RequestMatcher $matcher, HttpAsyncClient $client, RequestInterface $request)
57+
{
58+
$this->addClient($client, $matcher);
59+
$matcher->matches($request)->willReturn(false);
60+
61+
$this->shouldThrow('Http\Client\Exception\RequestException')->duringSendAsyncRequest($request);
62+
}
63+
}

src/HttpClientRouter.php

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
<?php
2+
3+
namespace Http\Client\Common;
4+
5+
use Http\Client\Exception\RequestException;
6+
use Http\Client\HttpAsyncClient;
7+
use Http\Client\HttpClient;
8+
use Http\Message\RequestMatcher;
9+
use Psr\Http\Message\RequestInterface;
10+
11+
/**
12+
* Route a request to a specific client in the stack based using a RequestMatcher.
13+
*
14+
* @author Joel Wurtz <[email protected]>
15+
*/
16+
final class HttpClientRouter implements HttpClient, HttpAsyncClient
17+
{
18+
/**
19+
* @var array
20+
*/
21+
private $clients = [];
22+
23+
/**
24+
* {@inheritdoc}
25+
*/
26+
public function sendRequest(RequestInterface $request)
27+
{
28+
$client = $this->chooseHttpClient($request);
29+
30+
return $client->sendRequest($request);
31+
}
32+
33+
/**
34+
* {@inheritdoc}
35+
*/
36+
public function sendAsyncRequest(RequestInterface $request)
37+
{
38+
$client = $this->chooseHttpClient($request);
39+
40+
return $client->sendAsyncRequest($request);
41+
}
42+
43+
/**
44+
* Add a client to the router.
45+
*
46+
* @param HttpClient|HttpAsyncClient $client
47+
* @param RequestMatcher $requestMatcher
48+
*/
49+
public function addClient($client, RequestMatcher $requestMatcher)
50+
{
51+
$this->clients[] = [
52+
'matcher' => $requestMatcher,
53+
'client' => new FlexibleHttpClient($client),
54+
];
55+
}
56+
57+
/**
58+
* Choose an HTTP client given a specific request.
59+
*
60+
* @param RequestInterface $request
61+
*
62+
* @return HttpClient|HttpAsyncClient
63+
*/
64+
protected function chooseHttpClient(RequestInterface $request)
65+
{
66+
foreach ($this->clients as $client) {
67+
if ($client['matcher']->matches($request)) {
68+
return $client['client'];
69+
}
70+
}
71+
72+
throw new RequestException('No client found for the specified request', $request);
73+
}
74+
}

0 commit comments

Comments
 (0)