docs: rewrite JsonRpcBundle docs, add SDK docs, move them under docs/api
en/docs/api/rest-bundle/error_handling.md
new file +94
ā0
1
+
# Error handling
2
+
3
+
## Format
4
+
5
+
Every error of a REST call or document is returned as an [RFC 9457](https://www.rfc-editor.org/rfc/rfc9457) (problem details) document with the HTTP status of the error:
6
+
7
+
```json
8
+
{
9
+
"_error_object_standard": "RFC 9457",
10
+
"status": 400,
11
+
"type": "about:blank",
12
+
"instance": "/rest/catalog/items/42",
13
+
"title": "Ufo\\RestBundle\\Exceptions\\RestBadRequestException",
14
+
"detail": "Invalid Data for call method: catalog.update",
15
+
"detail-data": {
16
+
"title": ["This value is too short. It should have 3 characters or more."]
17
+
}
18
+
}
19
+
```
20
+
21
+
| Field | Value |
22
+
| --- | --- |
23
+
| `status` | the HTTP status, the same as the response status |
24
+
| `type` | always `about:blank` |
25
+
| `instance` | the request path |
26
+
| `title` | the REST exception class |
27
+
| `detail` | the error message |
28
+
| `detail-data` | only if the RPC error contains an array of data: per-parameter messages for validation and type errors |
29
+
30
+
Stack traces are not included in the document.
31
+
32
+
## How the status is chosen
33
+
34
+
The RPC core turns any method exception into an RPC error (the `rpc.error` event): exceptions from the `ufo-tech/rpc-exceptions` package keep their class and code, an argument `TypeError` becomes a parameter error, other exceptions are wrapped ([Error handling in JsonRpcBundle](/docs/api/json-rpc-bundle/error_handling)). The REST layer recreates the exception from the RPC error and converts it with the `RestErrorNormalizer` class:
35
+
36
+
| RPC exception | REST exception | Status |
37
+
| --- | --- | --- |
38
+
| `RpcJsonParseException` | `RestBadRequestException` | 400 |
39
+
| `RpcMethodNotFoundExceptionRpc` | `RestResourceNotFoundException` | 404 |
40
+
| `ConstraintsImposedException` | `RestValidationException` | 422 |
41
+
| `RpcBadParamException` (parameter validation and type errors) | `RestBadRequestException` | 400 |
42
+
| `RpcBadRequestException` | `RestBadRequestException` | 400 |
43
+
| `RpcInternalException`, `RpcRuntimeException` | `RestInternalServerErrorException` | 500 |
44
+
| `RpcLogicException` | `RestBadRequestException` | 400 |
45
+
| `RpcTokenNotSentException`, `RpcInvalidTokenException` | `RestUnauthorizedException` | 401 |
46
+
| `RpcDataNotFoundException` | `RestResourceNotFoundException` | 404 |
47
+
| `CustomApplicationException` | `RestApplicationException` | the exception code if it is an HTTP error code, otherwise 400 |
48
+
| any other | `RestBadRequestException` | the exception code if it is an HTTP error code, otherwise 400 |
49
+
50
+
The table is checked top to bottom with `instanceof`, so subclasses come before their parent classes. An HTTP error code is a code from the `RestErrorNormalizer::REST_ERROR_CODES` list (standard 4xx and 5xx codes). If an exception from any row of the table has such a code, the status is taken from it.
51
+
52
+
:::info
53
+
The `404` row for `RpcMethodNotFoundExceptionRpc`, the `422` row for `ConstraintsImposedException` and keeping the HTTP code of an application error are available since version 1.3. In 1.0ā1.2 these cases returned `400`. See [Fixed issues](/docs/api/rest-bundle/developers/known_issues/fixed).
54
+
:::
55
+
56
+
## REST layer errors
57
+
58
+
| Situation | Exception | Status |
59
+
| --- | --- | --- |
60
+
| no REST route for the path, unknown version, a method of another group | `RestResourceNotFoundException` | 404 |
61
+
| the HTTP method is not allowed for the route | `RestResourceNotAllowedException` | 405 |
62
+
| invalid or scalar JSON body | `RestBadRequestException` | 400 |
63
+
| token not sent or invalid | `RestUnauthorizedException` | 401 |
64
+
65
+
## Returning a specific status from a method
66
+
67
+
Throw an RPC exception from the table or an exception with an HTTP code:
68
+
69
+
```php
70
+
use Ufo\RpcError\CustomApplicationException;
71
+
use Ufo\RpcError\RpcDataNotFoundException;
72
+
73
+
/**
74
+
* @throws RpcDataNotFoundException
75
+
* @throws CustomApplicationException
76
+
*/
77
+
#[Route('/items/{id}', name: 'item', methods: ['GET'])]
78
+
public function item(int $id): array
79
+
{
80
+
$item = $this->repository->find($id) ?? throw new RpcDataNotFoundException('Item is not found'); // 404
81
+
if ($item->isClosed()) {
82
+
throw new CustomApplicationException('Item is closed', 409); // 409
83
+
}
84
+
return $item->toArray();
85
+
}
86
+
```
87
+
88
+
Via JSON-RPC the same exceptions produce ordinary RPC errors, so one method serves both protocols. The `@throws` tags add these statuses to the [OpenAPI documentation](/docs/api/rest-bundle/documentation).
89
+
90
+
Notes:
91
+
92
+
* An exception with code `0` becomes an internal RPC error and returns `500`.
93
+
* RPC core validation errors (`#[RPC\Assertions]`, parameter types) return `400` with `detail-data`. `422` applies only to a `ConstraintsImposedException` that reaches the REST layer directly.
94
+
* An unknown method or path gives `404`, but a wrong HTTP method for an existing path gives `405`.