Обробка помилок

← Обробка помилок

Ashterix

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`.