fastapi/docs/uk/docs/tutorial/handling-errors.md

256 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Обробка Помилок
Є багато ситуацій, коли потрібно повідомити клієнта, який використовує Ваш API, про помилку.
Цим клієнтом може бути браузер із фронтендом, код іншого розробника, IoT-пристрій тощо.
Можливо, Вам потрібно повідомити клієнта, що:
* У нього недостатньо прав для виконання цієї операції.
* Він не має доступу до цього ресурсу.
* Елемент, до якого він намагається отримати доступ, не існує.
* тощо.
У таких випадках зазвичай повертається **HTTP статус-код** в діапазоні **400** (від 400 до 499).
Це схоже на HTTP статус-коди 200 (від 200 до 299). Ці "200" статус-коди означають, що запит пройшов успішно.
Статус-коди в діапазоні 400 означають, що сталася помилка з боку клієнта.
Пам'ятаєте всі ці помилки **404 Not Found** (і жарти про них)?
## Використання `HTTPException`
Щоб повернути HTTP-відповіді з помилками клієнту, використовуйте `HTTPException`.
### Імпорт `HTTPException`
{* ../../docs_src/handling_errors/tutorial001.py hl[1] *}
### Використання `HTTPException` у коді
`HTTPException` — це звичайна помилка Python із додатковими даними, які стосуються API.
Оскільки це помилка Python, Ви не `повертаєте` його, а `генеруєте` (генеруєте помилку).
Це також означає, що якщо Ви перебуваєте всередині допоміжної функції, яку викликаєте всередині своєї *функції операції шляху*, і там генеруєте `HTTPException`, всередині цієї допоміжної функції, то решта коду в *функції операції шляху* не буде виконана. Запит одразу завершиться, і HTTP-помилка з `HTTPException` буде надіслана клієнту.
Перевага використання `генерації` (raise) помилки замість `повернення` значення (return) стане більш очевидним в розділі про Залежності та Безпеку.
У цьому прикладі, якщо клієнт запитує елемент за ID, якого не існує, буде згенеровано помилку зі статус-кодом `404`:
{* ../../docs_src/handling_errors/tutorial001.py hl[11] *}
### Отримана відповідь
Якщо клієнт робить запит за шляхом `http://example.com/items/foo` (де `item_id` `"foo"`), він отримає статус-код 200 і JSON відповідь:
```JSON
{
"item": "The Foo Wrestlers"
}
```
Але якщо клієнт робить запит на `http://example.com/items/bar` (де `item_id` має не існуюче значення `"bar"`), то отримає статус-код 404 (помилка "не знайдено") та відповідь:
```JSON
{
"detail": "Item not found"
}
```
/// tip | Порада
Під час виклику `HTTPException` Ви можете передати будь-яке значення, яке може бути перетворене в JSON, як параметр `detail`, а не лише рядок (`str`).
Ви можете передати `dict`, `list` тощо.
Вони обробляються автоматично за допомогою **FastAPI** та перетворюються в JSON.
///
## Додавання власних заголовків
Іноді потрібно додати власні заголовки до HTTP-помилки, наприклад, для певних типів безпеки.
Ймовірно, Вам не доведеться використовувати це безпосередньо у своєму коді.
Але якщо Вам знадобиться це для складного сценарію, Ви можете додати власні заголовки:
{* ../../docs_src/handling_errors/tutorial002.py hl[14] *}
## Встановлення власних обробників помилок
Ви можете додати власні обробники помилок за допомогою <a href="https://www.starlette.dev/exceptions/" class="external-link" target="_blank">тих самих утиліт обробки помилок зі Starlette</a>.
Припустимо, у Вас є власний обʼєкт помилки `UnicornException`, яке Ви (або бібліотека, яку Ви використовуєте) може `згенерувати` (`raise`).
І Ви хочете обробляти це виключення глобально за допомогою FastAPI.
Ви можете додати власний обробник виключень за допомогою `@app.exception_handler()`:
{* ../../docs_src/handling_errors/tutorial003.py hl[5:7,13:18,24] *}
Тут, якщо Ви звернетеся до `/unicorns/yolo`, то згенерується помилка `UnicornException`.
Але вона буде оброблена функцією-обробником `unicorn_exception_handler`.
Отже, Ви отримаєте зрозумілу помилку зі HTTP-статусом `418` і JSON-відповіддю:
```JSON
{"message": "Oops! yolo did something. There goes a rainbow..."}
```
/// note | Технічні деталі
Ви також можете використовувати `from starlette.requests import Request` і `from starlette.responses import JSONResponse`.
**FastAPI** надає ті самі `starlette.responses`, що й `fastapi.responses`, просто для зручності розробника. Але більшість доступних відповідей надходять безпосередньо зі Starlette. Те ж саме стосується і `Request`.
///
## Перевизначення обробників помилок за замовчуванням
**FastAPI** має кілька обробників помилок за замовчуванням.
Ці обробники відповідають за повернення стандартних JSON-відповідей, коли Ви `генеруєте` (`raise`) `HTTPException`, а також коли запит містить некоректні дані.
Ви можете перевизначити ці обробники, створивши власні.
### Перевизначення помилок валідації запиту
Коли запит містить некоректні дані, **FastAPI** генерує `RequestValidationError`.
І також включає обробник помилок за замовчуванням для нього.
Щоб перевизначити його, імпортуйте `RequestValidationError` і використовуйте його з `@app.exception_handler(RequestValidationError)` для декорування обробника помилок.
Обробник помилок отримує `Request` і саму помилку.
{* ../../docs_src/handling_errors/tutorial004.py hl[2,14:16] *}
Тепер, якщо Ви перейдете за посиланням `/items/foo`, замість того, щоб отримати стандартну JSON-помилку:
```JSON
{
"detail": [
{
"loc": [
"path",
"item_id"
],
"msg": "value is not a valid integer",
"type": "type_error.integer"
}
]
}
```
Ви отримаєте текстову версію:
```
1 validation error
path -> item_id
value is not a valid integer (type=type_error.integer)
```
#### `RequestValidationError` проти `ValidationError`
/// warning | Увага
Це технічні деталі, які Ви можете пропустити, якщо вони зараз не важливі для Вас.
///
`RequestValidationError` є підкласом Pydantic <a href="https://docs.pydantic.dev/latest/concepts/models/#error-handling" class="external-link" target="_blank">`ValidationError`</a>.
**FastAPI** використовує його для того, якщо Ви використовуєте модель Pydantic у `response_model` і у ваших даних є помилка, Ви побачили помилку у своєму журналі.
Але клієнт/користувач не побачить її. Натомість клієнт отримає "Internal Server Error" зі статусом HTTP `500`.
Так має бути, якщо у Вас виникла `ValidationError` Pydantic у *відповіді* або деінде у вашому коді (не у *запиті* клієнта), це насправді є помилкою у Вашому коді.
І поки Ви її виправляєте, клієнти/користувачі не повинні мати доступу до внутрішньої інформації про помилку, оскільки це може призвести до вразливості безпеки.
### Перевизначення обробника помилок `HTTPException`
Аналогічно, Ви можете перевизначити обробник `HTTPException`.
Наприклад, Ви можете захотіти повернути текстову відповідь замість JSON для цих помилок:
{* ../../docs_src/handling_errors/tutorial004.py hl[3:4,9:11,22] *}
/// note | Технічні деталі
Ви також можете використовувати `from starlette.responses import PlainTextResponse`.
**FastAPI** надає ті самі `starlette.responses`, що й `fastapi.responses`, просто для зручності розробника. Але більшість доступних відповідей надходять безпосередньо зі Starlette.
///
### Використання тіла `RequestValidationError`
`RequestValidationError` містить `body`, який він отримав із некоректними даними.
Ви можете використовувати це під час розробки свого додатка, щоб логувати тіло запиту та налагоджувати його, повертати користувачеві тощо.
{* ../../docs_src/handling_errors/tutorial005.py hl[14] *}
Тепер спробуйте надіслати некоректний елемент, наприклад:
```JSON
{
"title": "towel",
"size": "XL"
}
```
Ви отримаєте відповідь, яка повідомить Вам, які саме дані є некоректні у вашому тілі запиту:
```JSON hl_lines="12-15"
{
"detail": [
{
"loc": [
"body",
"size"
],
"msg": "value is not a valid integer",
"type": "type_error.integer"
}
],
"body": {
"title": "towel",
"size": "XL"
}
}
```
#### `HTTPException` FastAPI проти `HTTPException` Starlette
**FastAPI** має власний `HTTPException`.
І клас помилки `HTTPException` в **FastAPI** успадковується від класу помилки `HTTPException` в Starlette.
Єдина різниця полягає в тому, що `HTTPException` в **FastAPI** приймає будь-які дані, які можна перетворити на JSON, для поля `detail`, тоді як `HTTPException` у Starlette приймає тільки рядки.
Отже, Ви можете продовжувати використовувати `HTTPException` в **FastAPI** як зазвичай у своєму коді.
Але коли Ви реєструєте обробник виключень, слід реєструвати його для `HTTPException` зі Starlette.
Таким чином, якщо будь-яка частина внутрішнього коду Starlette або розширення чи плагін Starlette згенерує (raise) `HTTPException`, Ваш обробник зможе перехопити та обробити її.
У цьому прикладі, щоб мати можливість використовувати обидва `HTTPException` в одному коді, помилка Starlette перейменовується на `StarletteHTTPException`:
```Python
from starlette.exceptions import HTTPException as StarletteHTTPException
```
### Повторне використання обробників помилок **FastAPI**
Якщо Ви хочете використовувати помилки разом із такими ж обробниками помилок за замовчуванням, як у **FastAPI**, Ви можете імпортувати та повторно використовувати їх із `fastapi.exception_handlers`:
{* ../../docs_src/handling_errors/tutorial006.py hl[2:5,15,21] *}
У цьому прикладі Ви просто використовуєте `print` для виведення дуже інформативного повідомлення, але Ви зрозуміли основну ідею. Ви можете обробити помилку та повторно використовувати обробники помилок за замовчуванням.