# Обробка помилок { #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_py39.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_py39.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_py39.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_py39.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_py39.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_py39.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_py39.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_py39.py hl[2:5,15,21] *}

У цьому прикладі ви просто друкуєте помилку з дуже виразним повідомленням, але ви зрозуміли основну ідею. Ви можете використовувати виключення, а потім просто повторно використати обробники виключень за замовчуванням.
