Skip to content

Commit 2becd93

Browse files
PHPSDK-155: Throw ApiUnavailableException when API returns 501/503 HTTP codes (#352)
1 parent e5053e0 commit 2becd93

File tree

5 files changed

+125
-29
lines changed

5 files changed

+125
-29
lines changed

src/Api/Base/Response.php

+11-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
use MultiSafepay\Api\Pager\Pager;
1010
use MultiSafepay\Exception\ApiException;
11+
use MultiSafepay\Exception\ApiUnavailableException;
1112

1213
/**
1314
* Class Response
@@ -37,7 +38,7 @@ class Response
3738
* @param string $json
3839
* @param array $context
3940
* @return Response
40-
* @throws ApiException
41+
* @throws ApiException|ApiUnavailableException
4142
*/
4243
public static function withJson(string $json, array $context = []): Response
4344
{
@@ -54,7 +55,7 @@ public static function withJson(string $json, array $context = []): Response
5455
* @param array $data
5556
* @param array $context
5657
* @param string $raw
57-
* @throws ApiException
58+
* @throws ApiException|ApiUnavailableException
5859
*/
5960
public function __construct(array $data, array $context = [], string $raw = '')
6061
{
@@ -82,6 +83,7 @@ public function __construct(array $data, array $context = [], string $raw = '')
8283
* @param array $context
8384
* @return void
8485
* @throws ApiException
86+
* @throws ApiUnavailableException
8587
*/
8688
private function validate(array $data, array $context = []): void
8789
{
@@ -96,6 +98,13 @@ private function validate(array $data, array $context = []): void
9698
[$errorCode, $errorInfo] = self::ERROR_INVALID_DATA_TYPE;
9799
}
98100

101+
if (in_array($context['http_response_code'], [501, 503])) {
102+
throw (new ApiUnavailableException(
103+
'The MultiSafepay API could not be reached',
104+
$context['http_response_code']
105+
));
106+
}
107+
99108
if (!$data['success']) {
100109
$context['raw_response_body'] = $this->raw;
101110
throw (new ApiException($errorInfo, $errorCode))->addContext($context);

src/Client/Client.php

+21-8
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
use MultiSafepay\Api\Base\RequestBodyInterface;
1212
use MultiSafepay\Api\Base\Response as ApiResponse;
1313
use MultiSafepay\Exception\ApiException;
14+
use MultiSafepay\Exception\ApiUnavailableException;
1415
use MultiSafepay\Exception\InvalidApiKeyException;
15-
use MultiSafepay\Exception\StrictModeException;
1616
use Psr\Http\Client\ClientExceptionInterface;
1717
use Psr\Http\Client\ClientInterface;
1818
use Psr\Http\Message\RequestFactoryInterface;
@@ -104,8 +104,7 @@ public function __construct(
104104
* @param RequestBodyInterface|null $requestBody
105105
* @param array $context
106106
* @return ApiResponse
107-
* @throws ClientExceptionInterface
108-
* @throws ApiException
107+
* @throws ClientExceptionInterface|ApiException|ApiUnavailableException
109108
*/
110109
public function createPostRequest(
111110
string $endpoint,
@@ -115,10 +114,12 @@ public function createPostRequest(
115114
$request = $this->createRequest($endpoint, self::METHOD_POST)
116115
->withBody($this->createBody($this->getRequestBody($requestBody)))
117116
->withHeader('Content-Length', strlen($this->getRequestBody($requestBody)));
117+
$httpResponse = $this->httpClient->sendRequest($request);
118118

119119
$context['headers'] = $request->getHeaders();
120120
$context['request_body'] = $this->getRequestBody($requestBody);
121-
$httpResponse = $this->httpClient->sendRequest($request);
121+
$context['http_response_code'] = $httpResponse->getStatusCode() ?? 0;
122+
122123
return ApiResponse::withJson($httpResponse->getBody()->getContents(), $context);
123124
}
124125

@@ -128,7 +129,7 @@ public function createPostRequest(
128129
* @param RequestBodyInterface|null $requestBody
129130
* @param array $context
130131
* @return ApiResponse
131-
* @throws ClientExceptionInterface|ApiException
132+
* @throws ClientExceptionInterface|ApiException|ApiUnavailableException
132133
*/
133134
public function createPatchRequest(
134135
string $endpoint,
@@ -138,10 +139,12 @@ public function createPatchRequest(
138139
$request = $this->createRequest($endpoint, self::METHOD_PATCH)
139140
->withBody($this->createBody($this->getRequestBody($requestBody)))
140141
->withHeader('Content-Length', strlen($this->getRequestBody($requestBody)));
142+
$httpResponse = $this->httpClient->sendRequest($request);
141143

142144
$context['headers'] = $request->getHeaders();
143145
$context['request_body'] = $this->getRequestBody($requestBody);
144-
$httpResponse = $this->httpClient->sendRequest($request);
146+
$context['http_response_code'] = $httpResponse->getStatusCode() ?? 0;
147+
145148
return ApiResponse::withJson($httpResponse->getBody()->getContents(), $context);
146149
}
147150

@@ -150,14 +153,17 @@ public function createPatchRequest(
150153
* @param array $parameters
151154
* @param array $context
152155
* @return ApiResponse
153-
* @throws ClientExceptionInterface|ApiException
156+
* @throws ClientExceptionInterface|ApiException|ApiUnavailableException
154157
*/
155158
public function createGetRequest(string $endpoint, array $parameters = [], array $context = []): ApiResponse
156159
{
157160
$request = $this->createRequest($endpoint, self::METHOD_GET, $parameters);
158161
$httpResponse = $this->httpClient->sendRequest($request);
162+
159163
$context['headers'] = $request->getHeaders();
160164
$context['request_params'] = $parameters;
165+
$context['http_response_code'] = $httpResponse->getStatusCode() ?? 0;
166+
161167
return ApiResponse::withJson($httpResponse->getBody()->getContents(), $context);
162168
}
163169

@@ -166,14 +172,17 @@ public function createGetRequest(string $endpoint, array $parameters = [], array
166172
* @param array $parameters
167173
* @param array $context
168174
* @return ApiResponse
169-
* @throws ClientExceptionInterface|ApiException
175+
* @throws ClientExceptionInterface|ApiException|ApiUnavailableException
170176
*/
171177
public function createDeleteRequest(string $endpoint, array $parameters = [], array $context = []): ApiResponse
172178
{
173179
$request = $this->createRequest($endpoint, self::METHOD_DELETE, $parameters);
174180
$httpResponse = $this->httpClient->sendRequest($request);
181+
175182
$context['headers'] = $request->getHeaders();
176183
$context['request_params'] = $parameters;
184+
$context['http_response_code'] = $httpResponse->getStatusCode() ?? 0;
185+
177186
return ApiResponse::withJson($httpResponse->getBody()->getContents(), $context);
178187
}
179188

@@ -202,6 +211,7 @@ public function getRequestUrl(string $endpoint, $parameters = []): string
202211
$parameters['locale'] = $this->locale;
203212
}
204213
$endpoint .= '?' . http_build_query($parameters);
214+
205215
return $this->url . $endpoint;
206216
}
207217

@@ -235,6 +245,7 @@ public function getHttpClient(): ClientInterface
235245
public function useStrictMode(bool $strictMode): Client
236246
{
237247
$this->strictMode = $strictMode;
248+
238249
return $this;
239250
}
240251

@@ -248,6 +259,7 @@ private function createRequest(string $endpoint, string $method, array $paramete
248259
{
249260
$url = $this->getRequestUrl($endpoint, $parameters);
250261
$requestFactory = $this->getRequestFactory();
262+
251263
return $requestFactory->createRequest($method, $url)
252264
->withHeader('api_key', $this->apiKey->get())
253265
->withHeader('accept-encoding', 'application/json')
@@ -261,6 +273,7 @@ private function createRequest(string $endpoint, string $method, array $paramete
261273
private function getRequestBody(RequestBodyInterface $requestBody): string
262274
{
263275
$requestBody->useStrictMode($this->strictMode);
276+
264277
return json_encode($requestBody->getData(), JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
265278
}
266279
}
+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php declare(strict_types=1);
2+
/**
3+
* Copyright © MultiSafepay, Inc. All rights reserved.
4+
* See DISCLAIMER.md for disclaimer details.
5+
*/
6+
7+
namespace MultiSafepay\Exception;
8+
9+
/**
10+
* Class ApiUnavailableException
11+
* @package MultiSafepay\Exception
12+
*/
13+
class ApiUnavailableException extends ApiException
14+
{
15+
}

tests/Unit/Api/Base/ResponseTest.php

+56-7
Original file line numberDiff line numberDiff line change
@@ -3,52 +3,101 @@
33

44
use MultiSafepay\Api\Base\Response;
55
use MultiSafepay\Exception\ApiException;
6+
use MultiSafepay\Exception\ApiUnavailableException;
67
use PHPUnit\Framework\TestCase;
78

89
class ResponseTest extends TestCase
910
{
1011
/**
1112
* @covers \MultiSafepay\Api\Base\Response::getResponseData
1213
* @covers \MultiSafepay\Api\Base\Response::withJson
14+
*
15+
* @return void
16+
* @throws ApiException
17+
* @throws ApiUnavailableException
1318
*/
1419
public function testWithJsonAndResponseData()
1520
{
1621
$json = json_encode(['success' => 1, 'data' => ['foo' => 'bar']]);
17-
$response = Response::withJson($json);
22+
$response = Response::withJson($json, ['http_response_code' => 200]);
1823
$data = $response->getResponseData();
24+
$this->assertInstanceOf(Response::class, $response);
1925
$this->assertArrayHasKey('foo', $data);
2026
}
2127

2228
/**
2329
* @covers \MultiSafepay\Api\Base\Response::withJson
30+
*
31+
* @return void
32+
* @throws ApiException
33+
* @throws ApiUnavailableException
2434
*/
25-
public function testWithUnknownData()
35+
public function testWithUnknownDataThrowsApiException()
2636
{
2737
$this->expectException(ApiException::class);
2838
$this->expectExceptionMessage('Unknown data');
2939
$json = json_encode(['foo' => 'bar']);
30-
Response::withJson($json);
40+
Response::withJson($json, ['http_response_code' => 200]);
3141
}
3242

3343
/**
3444
* @covers \MultiSafepay\Api\Base\Response::withJson
45+
*
46+
* @return void
47+
* @throws ApiException
48+
* @throws ApiUnavailableException
3549
*/
36-
public function testWithNoSuccessButUnknownData()
50+
public function testWithNoSuccessButUnknownDataThrowsApiException()
3751
{
3852
$this->expectException(ApiException::class);
3953
$this->expectExceptionMessage('Unknown data');
4054
$json = json_encode(['success' => 0, 'data' => ['foo' => 'bar']]);
41-
Response::withJson($json);
55+
Response::withJson($json, ['http_response_code' => 200]);
4256
}
4357

4458
/**
4559
* @covers \MultiSafepay\Api\Base\Response::withJson
60+
*
61+
* @return void
62+
* @throws ApiException
63+
* @throws ApiUnavailableException
4664
*/
47-
public function testWithNoSuccess()
65+
public function testWithNoSuccessThrowsApiException()
4866
{
4967
$this->expectException(ApiException::class);
5068
$this->expectExceptionMessage('bar');
5169
$json = json_encode(['success' => 0, 'error_code' => 42, 'error_info' => 'bar']);
52-
Response::withJson($json);
70+
Response::withJson($json, ['http_response_code' => 200]);
71+
}
72+
73+
/**
74+
* @covers \MultiSafepay\Api\Base\Response::withJson
75+
*
76+
* @return void
77+
* @throws ApiException
78+
* @throws ApiUnavailableException
79+
*/
80+
public function testWithJsonThrowsApiUnavailableExceptionOnInvalidHttpResponseCode()
81+
{
82+
$this->expectException(ApiUnavailableException::class);
83+
$json = json_encode(['data' => ['foo' => 'bar'], 'success' => false]);
84+
Response::withJson($json, ['http_response_code' => 503]);
85+
86+
$this->expectException(ApiUnavailableException::class);
87+
Response::withJson($json, ['http_response_code' => 501]);
88+
}
89+
90+
/**
91+
* @covers \MultiSafepay\Api\Base\Response::withJson
92+
*
93+
* @return void
94+
* @throws ApiException
95+
* @throws ApiUnavailableException
96+
*/
97+
public function testGetRawDataReturnsRawJson()
98+
{
99+
$json = json_encode(['data' => ['foo' => 'bar'], 'success' => true]);
100+
$response = Response::withJson($json, ['http_response_code' => 200]);
101+
$this->assertEquals($json, $response->getRawData());
53102
}
54103
}

tests/Unit/Api/ResponseTest.php

+22-12
Original file line numberDiff line numberDiff line change
@@ -39,21 +39,31 @@ public function testGetResponseDataWithErrors()
3939

4040
$this->expectExceptionCode(42);
4141
$this->expectExceptionMessage('Sample error message');
42-
new Response([
43-
'data' => ['foo' => 'bar'],
44-
'success' => 0,
45-
'error_code' => 42,
46-
'error_info' => 'Sample error message',
47-
]);
42+
new Response(
43+
[
44+
'data' => ['foo' => 'bar'],
45+
'success' => 0,
46+
'error_code' => 42,
47+
'error_info' => 'Sample error message',
48+
],
49+
[
50+
'http_response_code' => 200,
51+
]
52+
);
4853

4954
$this->expectExceptionCode(42);
5055
$this->expectExceptionMessage('Sample error message');
51-
new Response([
52-
'data' => ['foo' => 'bar'],
53-
'success' => 0,
54-
'error_code' => 42,
55-
'error_info' => 'Sample error message',
56-
]);
56+
new Response(
57+
[
58+
'data' => ['foo' => 'bar'],
59+
'success' => 0,
60+
'error_code' => 42,
61+
'error_info' => 'Sample error message',
62+
],
63+
[
64+
'http_response_code' => 200,
65+
]
66+
);
5767

5868
$this->expectExceptionCode(Response::ERROR_UNKNOWN_DATA[0]);
5969
$this->expectExceptionMessage(Response::ERROR_UNKNOWN_DATA[1]);

0 commit comments

Comments
 (0)