docs: rewrite JsonRpcBundle docs, add SDK docs, move them under docs/api
uk/docs/api/rest-bundle/error_handling.md
новий файл +94
−0
1
+
# Обробка помилок
2
+
3
+
## Формат
4
+
5
+
Кожна помилка REST-виклику чи документа повертається як документ [RFC 9457](https://www.rfc-editor.org/rfc/rfc9457) (problem details) з HTTP-статусом помилки:
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
+
| Поле | Значення |
22
+
| --- | --- |
23
+
| `status` | HTTP-статус, той самий, що й статус відповіді |
24
+
| `type` | завжди `about:blank` |
25
+
| `instance` | шлях запиту |
26
+
| `title` | клас REST-винятку |
27
+
| `detail` | повідомлення помилки |
28
+
| `detail-data` | лише якщо RPC-помилка містить масив даних: повідомлення по параметрах для помилок валідації й типів |
29
+
30
+
Трейси в документ не потрапляють.
31
+
32
+
## Як вибирається статус
33
+
34
+
Ядро RPC перетворює будь-який виняток методу на RPC-помилку (подія `rpc.error`): винятки пакета `ufo-tech/rpc-exceptions` зберігають клас і код, `TypeError` аргументу стає помилкою параметра, інші винятки обгортаються ([Обробка помилок у JsonRpcBundle](/docs/api/json-rpc-bundle/error_handling)). REST-шар відтворює виняток з RPC-помилки й перетворює його класом `RestErrorNormalizer`:
35
+
36
+
| RPC-виняток | REST-виняток | Статус |
37
+
| --- | --- | --- |
38
+
| `RpcJsonParseException` | `RestBadRequestException` | 400 |
39
+
| `RpcMethodNotFoundExceptionRpc` | `RestResourceNotFoundException` | 404 |
40
+
| `ConstraintsImposedException` | `RestValidationException` | 422 |
41
+
| `RpcBadParamException` (помилки валідації й типів параметрів) | `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` | код винятку, якщо це HTTP-код помилки, інакше 400 |
48
+
| будь-який інший | `RestBadRequestException` | код винятку, якщо це HTTP-код помилки, інакше 400 |
49
+
50
+
Таблиця перевіряється згори донизу через `instanceof`, тому підкласи стоять перед батьківськими класами. HTTP-кодом помилки вважається код із переліку `RestErrorNormalizer::REST_ERROR_CODES` (стандартні коди 4xx і 5xx). Якщо такий код має виняток із будь-якого рядка таблиці, статус береться з нього.
51
+
52
+
:::info
53
+
Рядки `404` для `RpcMethodNotFoundExceptionRpc`, `422` для `ConstraintsImposedException` і збереження HTTP-коду прикладної помилки — з версії 1.3. У 1.0–1.2 ці випадки повертали `400`. Див. [Виправлені помилки](/docs/api/rest-bundle/developers/known_issues/fixed).
54
+
:::
55
+
56
+
## Помилки REST-шару
57
+
58
+
| Ситуація | Виняток | Статус |
59
+
| --- | --- | --- |
60
+
| немає REST-маршруту для шляху, невідома версія, метод іншої групи | `RestResourceNotFoundException` | 404 |
61
+
| HTTP-метод не дозволено для маршруту | `RestResourceNotAllowedException` | 405 |
62
+
| некоректне або скалярне JSON-тіло | `RestBadRequestException` | 400 |
63
+
| токен не передано або він недійсний | `RestUnauthorizedException` | 401 |
64
+
65
+
## Як повернути потрібний статус з методу
66
+
67
+
Киньте RPC-виняток з таблиці або виняток з HTTP-кодом:
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
+
Через JSON-RPC ті самі винятки дають звичайні RPC-помилки, тож один метод обслуговує обидва протоколи. Теги `@throws` додають ці статуси в [документацію OpenAPI](/docs/api/rest-bundle/documentation).
89
+
90
+
Примітки:
91
+
92
+
* Виняток із кодом `0` стає внутрішньою RPC-помилкою і повертає `500`.
93
+
* Помилки валідації ядра RPC (`#[RPC\Assertions]`, типи параметрів) повертають `400` з `detail-data`. `422` застосовується лише до `ConstraintsImposedException`, що доходить до REST-шару напряму.
94
+
* Невідомий метод чи шлях — `404`, але неправильний HTTP-метод для наявного шляху — `405`.