JavaRush /Курсы /Модуль 4: FastAPI /Настройка глобального обработчика ошибок в FastAPI

Настройка глобального обработчика ошибок в FastAPI

Модуль 4: FastAPI
20 уровень , 8 лекция
Открыта

Представьте: ваше приложение отлично справляется со своей задачей, всё работает, пользователи довольны. Но вдруг — бац! — прилетает ошибка, которую вы не предусмотрели. Может, клиент отправил неожиданные данные, а, может, вы забыли проверить какой-то тип — и всё, приложение рушится или возвращает нечто странное.

Чтобы такие сюрпризы не превращались в кошмар, нужен глобальный обработчик ошибок. Он подстрахует вас на случай, если где-то что-то пошло не так и локальная обработка не сработала. Такой обработчик может красиво вернуть понятное сообщение пользователю, записать ошибку в лог для анализа, и, самое главное, не выдать наружу чувствительные детали вроде отладочной информации или трейса.


Как работает глобальный обработчик в FastAPI?

FastAPI предоставляет удобный способ настройки глобального обработчика ошибок через специальный декоратор @app.exception_handler. Он позволяет зарегистрировать обработчик для всех или определённых типов исключений.

Приведём пример глобального обработчика.

Предположим, у нас есть API для работы с заметками:


from fastapi import FastAPI

app = FastAPI()

@app.get("/notes/{note_id}")
async def get_note(note_id: int):
    # Здесь может возникнуть ошибка, если ID недопустим
    if note_id < 0:
        raise ValueError("ID должен быть положительным числом")
    return {"note_id": note_id, "content": "Заметка найдена!"}

Если пользователь передаст отрицательный note_id, Python выбросит исключение ValueError, которое, если не обработать, покажет пользователю нечитабельный текст ошибки. Теперь мы настроим глобальный обработчик для таких ситуаций.

Настройка глобального обработчика через @app.exception_handler

Глобальные обработчики настраиваются следующим образом:


from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse

app = FastAPI()

# Глобальный обработчик для исключений ValueError
@app.exception_handler(ValueError)
async def value_error_handler(request: Request, exc: ValueError):
    # Возвращаем JSON-ответ с описанием ошибки
    return JSONResponse(
        status_code=400,
        content={"error": "Некорректный запрос", "details": str(exc)},
    )

@app.get("/notes/{note_id}")
async def get_note(note_id: int):
    if note_id < 0:
        raise ValueError("ID должен быть положительным числом")
    return {"note_id": note_id, "content": "Заметка найдена!"}

Теперь, если пользователь передаст отрицательный note_id, он получит аккуратный JSON-ответ с описанием проблемы:


{
  "error": "Некорректный запрос",
  "details": "ID должен быть положительным числом"
}

Обработка всех необработанных исключений

Что, если ошибка не относится к ValueError? Для этого в FastAPI можно создать универсальный обработчик, который перехватывает все необработанные исключения.


@app.exception_handler(Exception)
async def global_exception_handler(request: Request, exc: Exception):
    # Логируем ошибку (например, с подробным трейсбэком)
    print(f"Unhandled error: {exc}")
    return JSONResponse(
        status_code=500,
        content={"error": "Произошла внутренняя ошибка сервера"}
    )

Теперь любое исключение, которое не перехватили другие обработчики, будет корректно обработано этим глобальным обработчиком.

Обработка кастомных исключений

Мы можем создать собственный класс исключений и обработчик для него. Например:


class BusinessLogicError(Exception):
    def __init__(self, message: str):
        self.message = message

@app.exception_handler(BusinessLogicError)
async def business_logic_error_handler(request: Request, exc: BusinessLogicError):
    return JSONResponse(
        status_code=400,
        content={"error": "Ошибка бизнес-логики", "details": exc.message},
    )

@app.get("/raise-business-error")
async def raise_error():
    raise BusinessLogicError("Произошло нарушение бизнес-правил")

При вызове эндпоинта /raise-business-error пользователь получит понятное сообщение:


{
  "error": "Ошибка бизнес-логики",
  "details": "Произошло нарушение бизнес-правил"
}

Интеграция с логированием

Глобальный обработчик часто используется для записи критических ошибок в журналы логов. Это можно сделать с помощью встроенного модуля Python logging:


import logging

logger = logging.getLogger(__name__)

@app.exception_handler(Exception)
async def global_exception_handler(request: Request, exc: Exception):
    # Логируем ошибку
    logger.error(f"Unhandled error: {exc}", exc_info=True)
    return JSONResponse(
        status_code=500,
        content={"error": "Произошла внутренняя ошибка сервера"}
    )

Совет: настройте ротацию логов и подключите мониторинговые системы (например, Sentry или ELK Stack).


Перехват ошибок внешних API

Работая с внешними API, можно комбинировать глобальный обработчик с библиотекой httpx. Например, если сторонний сервис возвращает ошибку:


import httpx

@app.get("/external-api")
async def call_external_api():
    async with httpx.AsyncClient() as client:
        response = await client.get("https://api.example.com/resource")
        if response.status_code != 200:
            raise ValueError("Ошибка внешнего API")
        return response.json()

Если возникнет ошибка, глобальный обработчик для ValueError обеспечит её обработку. Это делает работу с внешними сервисами более предсказуемой.


Типичные ошибки при настройке глобального обработчика

  1. Необработанные исключения: если вы забыли настроить обработчик для исключений типа Exception, неприятные ошибки могут доходить до конечных пользователей.
  2. Избыточный возврат информации: никогда не возвращайте стеки ошибок в JSON — это может содержать чувствительную информацию. Пользователям достаточно получить краткое сообщение.
  3. Логирование с отладочной информацией: не забывайте использовать уровни логирования (DEBUG, INFO, ERROR), чтобы ваши журналы были читаемыми.

Теперь ваш FastAPI-приложение подготовлено к обработке ошибок на всех уровнях: и локально, и глобально. Благодаря этому ваш API будет устойчивым, предсказуемым и легко отлаживаемым.

1
Задача
Модуль 4: FastAPI, 20 уровень, 8 лекция
Недоступна
Глобальный обработчик для стандартных ошибок
Глобальный обработчик для стандартных ошибок
1
Задача
Модуль 4: FastAPI, 20 уровень, 8 лекция
Недоступна
Обработка кастомных исключений
Обработка кастомных исключений
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ