mirror of https://github.com/tiangolo/fastapi.git
245 lines
14 KiB
Markdown
245 lines
14 KiB
Markdown
# Обробка помилок { #handling-errors }
|
||
|
||
Є багато ситуацій, коли вам потрібно повідомити про помилку клієнта, який використовує ваш API.
|
||
|
||
Цим клієнтом може бути браузер із фронтендом, код іншого розробника, IoT-пристрій тощо.
|
||
|
||
Можливо, вам потрібно повідомити клієнта, що:
|
||
|
||
* У нього недостатньо прав для виконання цієї операції.
|
||
* Він не має доступу до цього ресурсу.
|
||
* Елемент, до якого він намагається отримати доступ, не існує.
|
||
* тощо.
|
||
|
||
У таких випадках зазвичай повертається **HTTP статус-код** в діапазоні **400** (від 400 до 499).
|
||
|
||
Це схоже на HTTP статус-коди 200 (від 200 до 299). Ці «200» статус-коди означають, що якимось чином запит був «успішним».
|
||
|
||
Статус-коди в діапазоні 400 означають, що сталася помилка з боку клієнта.
|
||
|
||
Пам'ятаєте всі ці помилки **«404 Not Found»** (і жарти про них)?
|
||
|
||
## Використання `HTTPException` { #use-httpexception }
|
||
|
||
Щоб повернути HTTP-відповіді з помилками клієнту, використовуйте `HTTPException`.
|
||
|
||
### Імпорт `HTTPException` { #import-httpexception }
|
||
|
||
{* ../../docs_src/handling_errors/tutorial001_py310.py hl[1] *}
|
||
|
||
### Згенеруйте `HTTPException` у своєму коді { #raise-an-httpexception-in-your-code }
|
||
|
||
`HTTPException` — це звичайна помилка Python із додатковими даними, які стосуються API.
|
||
|
||
Оскільки це помилка Python, ви не `return` її, а `raise` її.
|
||
|
||
Це також означає, що якщо ви перебуваєте всередині допоміжної функції, яку викликаєте всередині своєї *функції операції шляху*, і там згенеруєте `HTTPException` всередині цієї допоміжної функції, то решта коду в *функції операції шляху* не буде виконана. Запит одразу завершиться, і HTTP-помилка з `HTTPException` буде надіслана клієнту.
|
||
|
||
Перевага генерації виключення замість повернення значення стане більш очевидною в розділі про залежності та безпеку.
|
||
|
||
У цьому прикладі, коли клієнт запитує елемент за ID, якого не існує, згенеруйте виключення зі статус-кодом `404`:
|
||
|
||
{* ../../docs_src/handling_errors/tutorial001_py310.py hl[11] *}
|
||
|
||
### Отримана відповідь { #the-resulting-response }
|
||
|
||
Якщо клієнт робить запит за шляхом `http://example.com/items/foo` (де `item_id` `"foo"`), він отримає HTTP статус-код 200 і JSON відповідь:
|
||
|
||
```JSON
|
||
{
|
||
"item": "The Foo Wrestlers"
|
||
}
|
||
```
|
||
|
||
Але якщо клієнт робить запит на `http://example.com/items/bar` (де `item_id` має не існуюче значення `"bar"`), то отримає HTTP статус-код 404 (помилка «не знайдено») та JSON відповідь:
|
||
|
||
```JSON
|
||
{
|
||
"detail": "Item not found"
|
||
}
|
||
```
|
||
|
||
/// tip | Порада
|
||
|
||
Під час генерації `HTTPException` ви можете передати будь-яке значення, яке може бути перетворене в JSON, як параметр `detail`, а не лише `str`.
|
||
|
||
Ви можете передати `dict`, `list` тощо.
|
||
|
||
Вони обробляються автоматично за допомогою **FastAPI** та перетворюються в JSON.
|
||
|
||
///
|
||
|
||
## Додавання власних заголовків { #add-custom-headers }
|
||
|
||
Є деякі ситуації, коли корисно мати можливість додавати власні заголовки до HTTP-помилки. Наприклад, для деяких типів безпеки.
|
||
|
||
Ймовірно, вам не доведеться використовувати це безпосередньо у своєму коді.
|
||
|
||
Але якщо вам знадобиться це для складного сценарію, ви можете додати власні заголовки:
|
||
|
||
{* ../../docs_src/handling_errors/tutorial002_py310.py hl[14] *}
|
||
|
||
## Встановлення власних обробників виключень { #install-custom-exception-handlers }
|
||
|
||
Ви можете додати власні обробники виключень за допомогою <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_py310.py hl[5:7,13:18,24] *}
|
||
|
||
Тут, якщо ви звернетеся до `/unicorns/yolo`, *операція шляху* згенерує (`raise`) `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`.
|
||
|
||
///
|
||
|
||
## Перевизначення обробників виключень за замовчуванням { #override-the-default-exception-handlers }
|
||
|
||
**FastAPI** має кілька обробників виключень за замовчуванням.
|
||
|
||
Ці обробники відповідають за повернення стандартних JSON-відповідей, коли ви `raise` `HTTPException`, а також коли запит містить некоректні дані.
|
||
|
||
Ви можете перевизначити ці обробники виключень власними.
|
||
|
||
### Перевизначення виключень валідації запиту { #override-request-validation-exceptions }
|
||
|
||
Коли запит містить некоректні дані, **FastAPI** внутрішньо генерує `RequestValidationError`.
|
||
|
||
І також включає обробник виключень за замовчуванням для нього.
|
||
|
||
Щоб перевизначити його, імпортуйте `RequestValidationError` і використовуйте його з `@app.exception_handler(RequestValidationError)` для декорування обробника виключень.
|
||
|
||
Обробник виключень отримає `Request` і саме виключення.
|
||
|
||
{* ../../docs_src/handling_errors/tutorial004_py310.py hl[2,14:19] *}
|
||
|
||
Тепер, якщо ви перейдете за посиланням `/items/foo`, замість того, щоб отримати стандартну JSON-помилку:
|
||
|
||
```JSON
|
||
{
|
||
"detail": [
|
||
{
|
||
"loc": [
|
||
"path",
|
||
"item_id"
|
||
],
|
||
"msg": "value is not a valid integer",
|
||
"type": "type_error.integer"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
ви отримаєте текстову версію:
|
||
|
||
```
|
||
Validation errors:
|
||
Field: ('path', 'item_id'), Error: Input should be a valid integer, unable to parse string as an integer
|
||
```
|
||
|
||
### Перевизначення обробника помилок `HTTPException` { #override-the-httpexception-error-handler }
|
||
|
||
Аналогічно, ви можете перевизначити обробник `HTTPException`.
|
||
|
||
Наприклад, ви можете захотіти повернути відповідь у вигляді простого тексту замість JSON для цих помилок:
|
||
|
||
{* ../../docs_src/handling_errors/tutorial004_py310.py hl[3:4,9:11,25] *}
|
||
|
||
/// note | Технічні деталі
|
||
|
||
Ви також можете використовувати `from starlette.responses import PlainTextResponse`.
|
||
|
||
**FastAPI** надає ті самі `starlette.responses`, що й `fastapi.responses`, просто для зручності для вас, розробника. Але більшість доступних відповідей надходять безпосередньо зі Starlette.
|
||
|
||
///
|
||
|
||
/// warning | Попередження
|
||
|
||
Пам’ятайте, що `RequestValidationError` містить інформацію про назву файлу та рядок, де сталася помилка валідації, щоб за потреби ви могли показати це у своїх логах із відповідною інформацією.
|
||
|
||
Але це означає, що якщо ви просто перетворите це на рядок і повернете цю інформацію напряму, ви можете розкрити трохи інформації про вашу систему, тому тут код витягає та показує кожну помилку незалежно.
|
||
|
||
///
|
||
|
||
### Використання тіла `RequestValidationError` { #use-the-requestvalidationerror-body }
|
||
|
||
`RequestValidationError` містить `body`, який він отримав із некоректними даними.
|
||
|
||
Ви можете використовувати це під час розробки свого додатка, щоб логувати тіло запиту та налагоджувати його, повертати користувачеві тощо.
|
||
|
||
{* ../../docs_src/handling_errors/tutorial005_py310.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 { #fastapis-httpexception-vs-starlettes-httpexception }
|
||
|
||
**FastAPI** має власний `HTTPException`.
|
||
|
||
І клас помилки `HTTPException` в **FastAPI** успадковується від класу помилки `HTTPException` у Starlette.
|
||
|
||
Єдина різниця полягає в тому, що `HTTPException` в **FastAPI** приймає будь-які дані, які можна перетворити на JSON, для поля `detail`, тоді як `HTTPException` у Starlette приймає тільки рядки.
|
||
|
||
Отже, ви можете продовжувати генерувати `HTTPException` **FastAPI** як зазвичай у своєму коді.
|
||
|
||
Але коли ви реєструєте обробник виключень, слід реєструвати його для `HTTPException` зі Starlette.
|
||
|
||
Таким чином, якщо будь-яка частина внутрішнього коду Starlette або розширення чи плагін Starlette згенерує Starlette `HTTPException`, ваш обробник зможе перехопити та обробити її.
|
||
|
||
У цьому прикладі, щоб мати можливість використовувати обидва `HTTPException` в одному коді, виключення Starlette перейменовується на `StarletteHTTPException`:
|
||
|
||
```Python
|
||
from starlette.exceptions import HTTPException as StarletteHTTPException
|
||
```
|
||
|
||
### Повторне використання обробників виключень **FastAPI** { #reuse-fastapis-exception-handlers }
|
||
|
||
Якщо ви хочете використовувати виключення разом із такими ж обробниками виключень за замовчуванням, як у **FastAPI**, ви можете імпортувати та повторно використати обробники виключень за замовчуванням із `fastapi.exception_handlers`:
|
||
|
||
{* ../../docs_src/handling_errors/tutorial006_py310.py hl[2:5,15,21] *}
|
||
|
||
У цьому прикладі ви просто друкуєте помилку з дуже виразним повідомленням, але ви зрозуміли основну ідею. Ви можете використовувати виключення, а потім просто повторно використати обробники виключень за замовчуванням.
|