Skip to content

Commit d5f9c64

Browse files
docs(errors): compatibility with laravel and improve (#2084)
1 parent 4814908 commit d5f9c64

File tree

1 file changed

+69
-18
lines changed

1 file changed

+69
-18
lines changed

core/errors.md

Lines changed: 69 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ API Platform comes with a powerful error system. It handles expected (such as fa
44
client or validation errors) as well as unexpected errors (PHP exceptions and errors).
55
API Platform automatically sends the appropriate HTTP status code to the client: `400` for expected errors, `500` for
66
unexpected ones. It also provides a description of the error in [the Hydra error format](https://www.hydra-cg.com/spec/latest/core/#description-of-http-status-codes-and-errors)
7-
or in the format described in the [RFC 7807](https://tools.ietf.org/html/rfc7807), depending of the format selected during the [content negotiation](content-negotiation.md).
7+
or in the format described in the [RFC 7807](https://tools.ietf.org/html/rfc7807), depending on the format selected during the [content negotiation](content-negotiation.md).
88

99
## Backward compatibility with < 3.1
1010

@@ -25,16 +25,33 @@ This can also be configured on an `ApiResource` or in an `HttpOperation`, for ex
2525

2626
## Exception status code decision
2727

28-
There are many ways of configuring the exception status code we recommend reading the guides on how to use an [Error Provider](https://api-platform.com/docs/guides/error-provider/) or create an [Error Resource](https://api-platform.com/docs/guides/error-resource/).
28+
There are many ways of configuring the exception status code we recommend reading the guides on how to use an
29+
[Error Provider](https://api-platform.com/docs/guides/error-provider/) or create an [Error Resource](https://api-platform.com/docs/guides/error-resource/).
2930

30-
1. we look at `exception_to_status` and take one if there's a match
31+
The decision works like this, if you are using API Platform with Symfony:
32+
33+
1. We look at `exception_to_status` and take one if there's a match
3134
2. If your exception is a `Symfony\Component\HttpKernel\Exception\HttpExceptionInterface` we get its status.
3235
3. If the exception is a `ApiPlatform\Metadata\Exception\ProblemExceptionInterface` and there is a status we use it
3336
4. Same for `ApiPlatform\Metadata\Exception\HttpExceptionInterface`
34-
5. We have some defaults `Symfony\Component\HttpFoundation\Exception\RequestExceptionInterface` => 400 and `ApiPlatform\Validator\Exception\ValidationException` => 422
35-
6. the status defined on an `ErrorResource`
37+
5. Use defaults for the following exceptions:
38+
- `Symfony\Component\HttpFoundation\Exception\RequestExceptionInterface` => 400
39+
- `ApiPlatform\Symfony\Validator\Exception\ValidationException` => 422
40+
6. The status defined on an `ErrorResource`
3641
7. 500 is the fallback
3742

43+
And like this, if you are using API Platform with Laravel:
44+
45+
1. Check an `exception_to_status` array and use its value if a match is found.
46+
2. If the exception implements `Illuminate\Contracts\Http\Exception\HttpResponseException`, retrieve its HTTP status.
47+
3. If the exception implements `App\Contracts\Exceptions\ProblemExceptionInterface` and a status is defined, use it.
48+
4. Similarly, check for `App\Contracts\Exceptions\HttpExceptionInterface`.
49+
5. Use defaults for the following exceptions:
50+
- `Illuminate\Http\Exceptions\HttpResponseException` => 400
51+
- `ApiPlatform\Symfony\Validator\Exception\ValidationException` => 422
52+
6. The status defined on an `ErrorResource`
53+
7. Fallback to 500.
54+
3855
## Exception to status
3956

4057
The framework also allows you to configure the HTTP status code sent to the clients when custom exceptions are thrown
@@ -45,7 +62,7 @@ configure API Platform to convert it to a `404 Not Found` error:
4562

4663
```php
4764
<?php
48-
// api/src/Exception/ProductNotFoundException.php
65+
// api/src/Exception/ProductNotFoundException.php with Symfony or app/Exception/ProductNotFoundException.php with Laravel
4966
namespace App\Exception;
5067
5168
final class ProductNotFoundException extends \Exception
@@ -56,11 +73,12 @@ final class ProductNotFoundException extends \Exception
5673

5774
```php
5875
<?php
59-
// api/src/EventSubscriber/ProductManager.php
76+
// api/src/EventSubscriber/ProductManager.php with Symfony or app/EventSubscriber/ProductManager.php with Laravel
77+
6078
namespace App\EventSubscriber;
6179
6280
use ApiPlatform\EventListener\EventPriorities;
63-
use App\Entity\Product;
81+
use App\ApiResource\Product;
6482
use App\Exception\ProductNotFoundException;
6583
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
6684
use Symfony\Component\HttpFoundation\Request;
@@ -92,11 +110,13 @@ final class ProductManager implements EventSubscriberInterface
92110
```
93111

94112
If you use the standard distribution of API Platform, this event listener will be automatically registered. If you use a
95-
custom installation, [learn how to register listeners](events.md#custom-event-listeners).
113+
custom installation, [learn how to extend API Platform](extending.md).
96114

97115
Then, configure the framework to catch `App\Exception\ProductNotFoundException` exceptions and convert them into `404`
98116
errors:
99117

118+
### Exception to status Configuration using Symfony
119+
100120
```yaml
101121
# config/packages/api_platform.yaml
102122
api_platform:
@@ -115,9 +135,32 @@ api_platform:
115135
App\Exception\ProductNotFoundException: 404 # Here is the handler for our custom exception
116136
```
117137

118-
Any type of `Exception` can be thrown, API Platform will convert it to a Symfony's `HttpException` (note that it means the exception will be flattened and lose all of its custom properties). The framework also takes
119-
care of serializing the error description according to the request format. For instance, if the API should respond in JSON-LD,
120-
the error will be returned in this format as well:
138+
### Exception to status Configuration using Laravel
139+
140+
```php
141+
<?php
142+
// config/api-platform.php
143+
return [
144+
// ....
145+
'exception_to_status' => [
146+
// The 3 following handlers are registered by default, keep those lines to prevent unexpected side effects
147+
Symfony\Component\Serializer\Exception\ExceptionInterface::class => 400,
148+
ApiPlatform\Exception\InvalidArgumentException::class => Illuminate\Http\Response::HTTP_BAD_REQUEST,
149+
ApiPlatform\ParameterValidator\Exception\ValidationExceptionInterface => 400,
150+
151+
//Validation exception
152+
ApiPlatform\Validator\Exception\ValidationException::class => Illuminate\Http\Response::HTTP_UNPROCESSABLE_ENTITY,
153+
154+
//Custom mapping
155+
App\Exception\ProductNotFoundException::class => 404 // Here is the handler for our custom exception
156+
],
157+
];
158+
```
159+
160+
Any type of `Exception` can be thrown, API Platform will convert it to a Symfony's `HttpException` (note that it means
161+
the exception will be flattened and lose all of its custom properties). The framework also takes care of serializing the
162+
error description according to the request format. For instance, if the API should respond in JSON-LD, the error will be
163+
returned in this format as well:
121164

122165
`GET /products/1234`
123166

@@ -133,7 +176,9 @@ the error will be returned in this format as well:
133176
### Message Scope
134177

135178
Depending on the status code you use, the message may be replaced with a generic one in production to avoid leaking unwanted information.
136-
If your status code is >= 500 and < 600, the exception message will only be displayed in debug mode (dev and test). In production, a generic message matching the status code provided will be shown instead. If you are using an unofficial HTTP code, a general message will be displayed.
179+
If your status code is >= 500 and < 600, the exception message will only be displayed in debug mode (dev and test).
180+
In production, a generic message matching the status code provided will be shown instead. If you are using an unofficial
181+
HTTP code, a general message will be displayed.
137182

138183
In any other cases, your exception message will be sent to end users.
139184

@@ -143,8 +188,8 @@ The `exceptionToStatus` configuration can be set on resources and operations:
143188

144189
```php
145190
<?php
146-
// api/src/Entity/Book.php
147-
namespace App\Entity;
191+
// api/src/ApiResource/Book.php with Symfony or app/ApiResource/Book.php with Laravel
192+
namespace App\ApiResource;
148193
149194
use ApiPlatform\Metadata\ApiResource;
150195
use ApiPlatform\Metadata\Get;
@@ -172,7 +217,8 @@ the global config.
172217

173218
## Control your exceptions
174219

175-
With `rfc_7807_compliant_errors` a few things happen. First Hydra exception are compatible with the JSON Problem specification. Default exception that are handled by API Platform in JSON will be returned as `application/problem+json`.
220+
With `rfc_7807_compliant_errors` a few things happen. First Hydra exception are compatible with the JSON Problem specification.
221+
Default exception that are handled by API Platform in JSON will be returned as `application/problem+json`.
176222

177223
To customize the API Platform response, replace the `api_platform.state.error_provider` with your own provider:
178224

@@ -202,7 +248,7 @@ final class ErrorProvider implements ProviderInterface
202248
// You don't have to use this, you can use a Response, an array or any object (preferably a resource that API Platform can handle).
203249
$error = Error::createFromException($exception, $status);
204250
205-
// care about hiding informations as this can be a security leak
251+
// care about hiding information as this can be a security leak
206252
if ($status >= 500) {
207253
$error->setDetail('Something went wrong');
208254
}
@@ -213,6 +259,7 @@ final class ErrorProvider implements ProviderInterface
213259
```
214260

215261
```yaml
262+
# The YAML syntax is only supported for Symfony
216263
api_platform.state.error_provider:
217264
class: 'App\State\ErrorProvider'
218265
tags:
@@ -223,6 +270,7 @@ api_platform.state.error_provider:
223270
Note that our validation exception have their own error provider at:
224271

225272
```yaml
273+
# The YAML syntax is only supported for Symfony
226274
api_platform.validator.state.error_provider:
227275
tags:
228276
- key: 'api_platform.validator.state.error_provider'
@@ -271,4 +319,7 @@ class Error extends \Exception implements ProblemExceptionInterface
271319
}
272320
```
273321

274-
We recommend using the `\ApiPlatform\Metadata\Exception\ProblemExceptionInterface` and the `\ApiPlatform\Metadata\Exception\HttpExceptionInterface`. For security reasons we add: `normalizationContext: ['ignored_attributes' => ['trace', 'file', 'line', 'code', 'message', 'traceAsString']]` because you usually don't want these. You can override this context value if you want.
322+
We recommend using the `\ApiPlatform\Metadata\Exception\ProblemExceptionInterface` and the
323+
`\ApiPlatform\Metadata\Exception\HttpExceptionInterface`. For security reasons we add: `normalizationContext: ['ignored_attributes'
324+
=> ['trace', 'file', 'line', 'code', 'message', 'traceAsString']]` because you usually don't want these. You can override
325+
this context value if you want.

0 commit comments

Comments
 (0)