Skip to content

Commit a80bec9

Browse files
committed
Error middleware that turns HTTP Exceptions in useful exceptions with errors
1 parent 245b975 commit a80bec9

File tree

4 files changed

+112
-6
lines changed

4 files changed

+112
-6
lines changed

composer.lock

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/ApiErrorException.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace ApiClients\Client\Github;
4+
5+
use Exception;
6+
use Throwable;
7+
8+
final class ApiErrorException extends Exception
9+
{
10+
/**
11+
* @var array
12+
*/
13+
private $context = [];
14+
15+
public static function create(string $message, int $code, Throwable $previous): self
16+
{
17+
return new self($message, $code, $previous);
18+
}
19+
20+
public static function createWithErrors(string $message, int $code, array $errors, Throwable $previous): self
21+
{
22+
$exception = new self($message, $code, $previous);
23+
$exception->setContext($errors);
24+
return $exception;
25+
}
26+
27+
public function getContext(): array
28+
{
29+
return $this->context;
30+
}
31+
32+
private function setContext(array $context)
33+
{
34+
$this->context = $context;
35+
}
36+
}

src/ApiSettings.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace ApiClients\Client\Github;
44

5+
use ApiClients\Client\Github\Middleware\ErrorMiddleware;
56
use ApiClients\Client\Github\Middleware\RateLimitStateMiddleware;
67
use ApiClients\Foundation\Hydrator\Options as HydratorOptions;
78
use ApiClients\Foundation\Options as FoundationOptions;
@@ -28,9 +29,10 @@ final class ApiSettings
2829
TransportOptions::MIDDLEWARE => [
2930
JsonDecodeMiddleware::class,
3031
JsonEncodeMiddleware::class,
31-
HttpExceptionsMiddleware::class,
3232
UserAgentMiddleware::class,
3333
RateLimitStateMiddleware::class,
34+
HttpExceptionsMiddleware::class,
35+
ErrorMiddleware::class,
3436
],
3537
TransportOptions::DEFAULT_REQUEST_OPTIONS => [
3638
UserAgentMiddleware::class => [

src/Middleware/ErrorMiddleware.php

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace ApiClients\Client\Github\Middleware;
4+
5+
use ApiClients\Client\Github\ApiErrorException;
6+
use ApiClients\Foundation\Middleware\Annotation\SecondLast;
7+
use ApiClients\Foundation\Middleware\MiddlewareInterface;
8+
use ApiClients\Foundation\Middleware\PostTrait;
9+
use ApiClients\Foundation\Middleware\PreTrait;
10+
use ApiClients\Foundation\Transport\ParsedContentsInterface;
11+
use ApiClients\Tools\Psr7\HttpStatusExceptions\BadRequestException;
12+
use ApiClients\Tools\Psr7\HttpStatusExceptions\UnprocessableEntityException;
13+
use React\Promise\CancellablePromiseInterface;
14+
use Throwable;
15+
use function React\Promise\reject;
16+
17+
final class ErrorMiddleware implements MiddlewareInterface
18+
{
19+
use PreTrait;
20+
use PostTrait;
21+
22+
/**
23+
* @param Throwable $throwable
24+
* @param string $transactionId
25+
* @param array $options
26+
* @return CancellablePromiseInterface
27+
* @SecondLast()
28+
*/
29+
public function error(
30+
Throwable $throwable,
31+
string $transactionId,
32+
array $options = []
33+
): CancellablePromiseInterface
34+
{
35+
if ($throwable instanceof UnprocessableEntityException ||
36+
$throwable instanceof BadRequestException
37+
) {
38+
$response = $throwable->getResponse();
39+
$body = $response->getBody();
40+
if (!($body instanceof ParsedContentsInterface)) {
41+
return reject($throwable);
42+
}
43+
$contents = $body->getParsedContents();
44+
$message = $contents['message'] ?? $throwable->getMessage();
45+
46+
if (isset($contents['errors'])) {
47+
return reject(
48+
ApiErrorException::createWithErrors(
49+
$message,
50+
$throwable->getCode(),
51+
$contents['errors'],
52+
$throwable
53+
)
54+
);
55+
}
56+
57+
return reject(
58+
ApiErrorException::create(
59+
$message,
60+
$throwable->getCode(),
61+
$throwable
62+
)
63+
);
64+
}
65+
66+
return reject($throwable);
67+
}
68+
}

0 commit comments

Comments
 (0)