Skip to content

Commit b669a37

Browse files
committed
A nice API to handle API errors
1 parent 4a41538 commit b669a37

File tree

7 files changed

+149
-7
lines changed

7 files changed

+149
-7
lines changed

src/Bridge/Symfony/Bundle/Test/Client.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ public function request(string $method, string $url, array $options = []): Respo
7575
(\is_array($options['body']) || $options['body'] instanceof \JsonSerializable) &&
7676
(
7777
$json ||
78-
false !== preg_match('#^application/(?:.+\+)?json$#', $options['headers']['content-type'][0])
78+
false !== preg_match('#^application/(?:.+\+)?json#', $options['headers']['content-type'][0])
7979
)
8080
) {
8181
// Encode the JSON
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <[email protected]>
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+
declare(strict_types=1);
13+
14+
namespace ApiPlatform\Core\Bridge\Symfony\Bundle\Test\Exception;
15+
16+
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
17+
18+
/**
19+
* Represents a 4xx response.
20+
*
21+
* @author Kévin Dunglas <[email protected]>
22+
*
23+
* @internal
24+
*/
25+
final class ClientException extends \RuntimeException implements ClientExceptionInterface
26+
{
27+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <[email protected]>
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+
declare(strict_types=1);
13+
14+
namespace ApiPlatform\Core\Bridge\Symfony\Bundle\Test;
15+
16+
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
17+
18+
/**
19+
* Thrown by responses' toArray() method when their content cannot be JSON-decoded.
20+
*
21+
* @author Kévin Dunglas <[email protected]>
22+
*
23+
* @internal
24+
*/
25+
final class JsonException extends \JsonException implements TransportExceptionInterface
26+
{
27+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <[email protected]>
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+
declare(strict_types=1);
13+
14+
namespace ApiPlatform\Core\Bridge\Symfony\Bundle\Test;
15+
16+
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
17+
18+
/**
19+
* Represents a 3xx response.
20+
*
21+
* @author Kévin Dunglas <[email protected]>
22+
*
23+
* @internal
24+
*/
25+
final class RedirectionException extends \RuntimeException implements RedirectionExceptionInterface
26+
{
27+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <[email protected]>
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+
declare(strict_types=1);
13+
14+
namespace ApiPlatform\Core\Bridge\Symfony\Bundle\Test;
15+
16+
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
17+
18+
/**
19+
* Represents a 5xx response.
20+
*
21+
* @author Kévin Dunglas <[email protected]>
22+
*
23+
* @internal
24+
*/
25+
final class ServerException extends \RuntimeException implements ServerExceptionInterface
26+
{
27+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <[email protected]>
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+
declare(strict_types=1);
13+
14+
namespace ApiPlatform\Core\Bridge\Symfony\Bundle\Test;
15+
16+
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
17+
18+
/**
19+
* @author Kévin Dunglas <[email protected]>
20+
*
21+
* @internal
22+
*/
23+
final class TransportException extends \RuntimeException implements TransportExceptionInterface
24+
{
25+
}

src/Bridge/Symfony/Bundle/Test/Response.php

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
namespace ApiPlatform\Core\Bridge\Symfony\Bundle\Test;
1515

16+
use ApiPlatform\Core\Bridge\Symfony\Bundle\Test\Exception\ClientException;
1617
use Symfony\Component\BrowserKit\Response as BrowserKitResponse;
1718
use Symfony\Component\HttpClient\Exception\JsonException;
1819
use Symfony\Component\HttpFoundation\Response as HttpFoundationResponse;
@@ -65,21 +66,29 @@ public function getInfo(string $type = null)
6566
return $this->info;
6667
}
6768

69+
/**
70+
* Checks the status, and try to extract message if appropriate.
71+
*/
6872
private function checkStatusCode()
6973
{
74+
$message = 'An error '.$this->info['http_code'].' occured.';
75+
if (isset($this->headers['content-type'][0]) && false !== preg_match('#^application/(?:.+\+)?json#', $this->headers['content-type'][0])) {
76+
if ($json = json_decode($this->content, true)) {
77+
// Try to extract the error message from Hydra or RFC 7807 error structures
78+
$message = $json['hydra:description'] ?? $json['hydra:title'] ?? $json['detail'] ?? $json['title'] ?? $message;
79+
}
80+
}
81+
7082
if (500 <= $this->info['http_code']) {
71-
throw new class('', $this->info['http_code']) extends \RuntimeException implements ServerExceptionInterface {
72-
};
83+
throw new ServerException($message, $this->info['http_code']);
7384
}
7485

7586
if (400 <= $this->info['http_code']) {
76-
throw new class('', $this->info['http_code']) extends \RuntimeException implements ClientExceptionInterface {
77-
};
87+
throw new ClientException($message, $this->info['http_code']);
7888
}
7989

8090
if (300 <= $this->info['http_code']) {
81-
throw new class('', $this->info['http_code']) extends \RuntimeException implements RedirectionExceptionInterface {
82-
};
91+
throw new RedirectionException($message, $this->info['http_code']);
8392
}
8493
}
8594

0 commit comments

Comments
 (0)