Skip to content

Commit dd3f974

Browse files
committed
added client
1 parent 0f5a0d9 commit dd3f974

File tree

4 files changed

+228
-0
lines changed

4 files changed

+228
-0
lines changed

src/Client/Client.php

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Setono\PostNord\Client;
6+
7+
use Psr\Http\Client\ClientExceptionInterface;
8+
use Psr\Http\Client\ClientInterface as HttpClientInterface;
9+
use Psr\Http\Message\RequestFactoryInterface;
10+
use Psr\Http\Message\StreamFactoryInterface;
11+
use Safe\Exceptions\JsonException;
12+
use Safe\Exceptions\StringsException;
13+
use function Safe\json_decode;
14+
use function Safe\json_encode;
15+
use Setono\PostNord\Exception\RequestFailedException;
16+
17+
final class Client implements ClientInterface
18+
{
19+
/**
20+
* @var HttpClientInterface
21+
*/
22+
private $httpClient;
23+
24+
/**
25+
* @var RequestFactoryInterface
26+
*/
27+
private $requestFactory;
28+
29+
/**
30+
* @var StreamFactoryInterface
31+
*/
32+
private $streamFactory;
33+
34+
/**
35+
* @var string
36+
*/
37+
private $apiKey;
38+
39+
/**
40+
* @var string
41+
*/
42+
private $baseUrl;
43+
44+
public function __construct(
45+
HttpClientInterface $httpClient,
46+
RequestFactoryInterface $requestFactory,
47+
StreamFactoryInterface $streamFactory,
48+
string $apiKey,
49+
string $baseUrl = 'https://api2.postnord.com'
50+
) {
51+
$this->httpClient = $httpClient;
52+
$this->requestFactory = $requestFactory;
53+
$this->streamFactory = $streamFactory;
54+
$this->apiKey = $apiKey;
55+
$this->baseUrl = $baseUrl;
56+
}
57+
58+
/**
59+
* @param string $endpoint
60+
* @param array $params
61+
*
62+
* @return array
63+
*
64+
* @throws ClientExceptionInterface
65+
* @throws JsonException
66+
* @throws StringsException
67+
*/
68+
public function get(string $endpoint, array $params = []): array
69+
{
70+
return $this->sendRequest('GET', $endpoint, $params);
71+
}
72+
73+
/**
74+
* @param string $endpoint
75+
* @param array $params
76+
* @param array $body
77+
*
78+
* @return array
79+
*
80+
* @throws ClientExceptionInterface
81+
* @throws JsonException
82+
* @throws StringsException
83+
*/
84+
public function post(string $endpoint, array $params = [], array $body = []): array
85+
{
86+
return $this->sendRequest('POST', $endpoint, $params, $body);
87+
}
88+
89+
/**
90+
* @param string $method
91+
* @param string $endpoint
92+
* @param array $params
93+
* @param array $body
94+
*
95+
* @return array
96+
*
97+
* @throws ClientExceptionInterface
98+
* @throws JsonException
99+
* @throws StringsException
100+
*/
101+
private function sendRequest(string $method, string $endpoint, array $params = [], array $body = []): array
102+
{
103+
$params = array_merge([
104+
'apikey' => $this->apiKey,
105+
], $params);
106+
107+
$url = $this->baseUrl.'/'.$endpoint.'?'.http_build_query($params, '', '&', PHP_QUERY_RFC3986);
108+
109+
$request = $this->requestFactory->createRequest($method, $url);
110+
111+
if (!empty($body)) {
112+
$request = $request->withBody($this->streamFactory->createStream(json_encode($body)));
113+
}
114+
115+
$response = $this->httpClient->sendRequest($request);
116+
117+
if (200 !== $response->getStatusCode()) {
118+
throw new RequestFailedException($request, $response, $response->getStatusCode());
119+
}
120+
121+
return (array) json_decode((string) $response->getBody(), true);
122+
}
123+
}

src/Client/ClientInterface.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Setono\PostNord\Client;
6+
7+
interface ClientInterface
8+
{
9+
/**
10+
* Sends a GET request to the specified endpoint with the given query params.
11+
*
12+
* @param string $endpoint
13+
* @param array $params
14+
*
15+
* @return array
16+
*/
17+
public function get(string $endpoint, array $params = []): array;
18+
19+
/**
20+
* Sends a POST request to the specified endpoint with the given query params and specified body.
21+
*
22+
* @param string $endpoint
23+
* @param array $params
24+
* @param array $body
25+
*
26+
* @return array
27+
*/
28+
public function post(string $endpoint, array $params = [], array $body = []): array;
29+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Setono\PostNord\Exception;
6+
7+
use Psr\Http\Message\RequestInterface;
8+
use Psr\Http\Message\ResponseInterface;
9+
use RuntimeException;
10+
use Safe\Exceptions\StringsException;
11+
use function Safe\sprintf;
12+
13+
final class RequestFailedException extends RuntimeException
14+
{
15+
private $request;
16+
private $response;
17+
private $statusCode;
18+
19+
/**
20+
* @param RequestInterface $request
21+
* @param ResponseInterface $response
22+
* @param int $statusCode
23+
*
24+
* @throws StringsException
25+
*/
26+
public function __construct(RequestInterface $request, ResponseInterface $response, int $statusCode)
27+
{
28+
$this->request = $request;
29+
$this->response = $response;
30+
$this->statusCode = $statusCode;
31+
32+
parent::__construct(sprintf('Request failed with status code %d', $this->statusCode));
33+
}
34+
35+
public function getRequest(): RequestInterface
36+
{
37+
return $this->request;
38+
}
39+
40+
public function getResponse(): ResponseInterface
41+
{
42+
return $this->response;
43+
}
44+
45+
public function getStatusCode(): int
46+
{
47+
return $this->statusCode;
48+
}
49+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Setono\PostNord\Exception;
6+
7+
use PHPUnit\Framework\TestCase;
8+
use Psr\Http\Message\RequestInterface;
9+
use Psr\Http\Message\ResponseInterface;
10+
11+
final class RequestFailedExceptionTest extends TestCase
12+
{
13+
/**
14+
* @test
15+
*/
16+
public function it_returns_correct_values(): void
17+
{
18+
$request = $this->createMock(RequestInterface::class);
19+
$response = $this->createMock(ResponseInterface::class);
20+
21+
$exception = new RequestFailedException($request, $response, 200);
22+
23+
$this->assertSame($request, $exception->getRequest());
24+
$this->assertSame($response, $exception->getResponse());
25+
$this->assertSame(200, $exception->getStatusCode());
26+
}
27+
}

0 commit comments

Comments
 (0)