Каков жизненный цикл обработки HTTP-запроса в FastAPI

Ответ

FastAPI, построенный на ASGI-фреймворке Starlette и библиотеке Pydantic, обрабатывает запросы в несколько четких и высокопроизводительных этапов.

Жизненный цикл запроса:

  1. Маршрутизация (Routing)

    • Starlette получает входящий HTTP-запрос.
    • Он сопоставляет HTTP-метод (GET, POST и т.д.) и путь запроса (например, /items/1) с соответствующей функцией-обработчиком (path operation function), определенной с помощью декоратора (@app.get("/items/{item_id}")).
  2. Извлечение и Валидация (Parsing & Validation)

    • FastAPI использует Pydantic для автоматического парсинга, приведения типов и валидации данных.
    • Данные извлекаются из пути, query-параметров, заголовков, cookie и тела запроса.
    • Если данные не соответствуют аннотациям типов или валидаторам в модели Pydantic, FastAPI автоматически прерывает цикл и возвращает клиенту ошибку 422 Unprocessable Entity с подробным JSON-описанием проблемы.
  3. Обработка Зависимостей (Dependency Injection)

    • FastAPI выполняет все зависимости, указанные для эндпоинта с помощью Depends.
    • Это может включать проверку аутентификации, получение сессии базы данных или выполнение другого общего кода.
    • Результаты выполнения зависимостей передаются в функцию-обработчик в качестве аргументов.
  4. Выполнение Кода Эндпоинта (Path Operation Execution)

    • Вызывается сама функция-обработчик с уже валидированными данными и результатами работы зависимостей.
    • FastAPI эффективно обрабатывает как асинхронные (async def), так и синхронные (def) функции. Синхронные функции выполняются в отдельном пуле потоков, чтобы не блокировать основной цикл событий (event loop).
  5. Формирование Ответа (Response Generation)

    • Результат, возвращаемый функцией, сериализуется (обычно в JSON).
    • FastAPI упаковывает данные в HTTP-ответ с соответствующим статус-кодом, заголовками и телом.

Пример с валидацией:

from fastapi import FastAPI
from pydantic import BaseModel, Field

app = FastAPI()

class Item(BaseModel):
    name: str
    price: float = Field(..., gt=0) # Цена должна быть больше нуля

@app.post("/items/")
async def create_item(item: Item):
    # Этот код выполнится только если 'item' пройдет валидацию Pydantic
    return {"status": "success", "item": item}

Если отправить POST-запрос с {"name": "Apple", "price": -1}, FastAPI автоматически вернет ошибку 422 еще до вызова функции create_item.

Ответ 18+ 🔞

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

Представь, прилетает к тебе запрос, типа «дай мне там че-нибудь». И начинается, сука, целый спектакль, ёперный театр!

Вот как оно там, в этой кухне, происходит:

  1. Маршрутизация, блядь (Routing) Starlette, этот основательный чувак, хватает входящий запрос и начинает его шарить. «Ты куда, сука? На /items/1? И метод у тебя GET? Ага, ща, я знаю, кто за это отвечает!» — и находит нужную функцию, которую ты обвешал декораторами, как ёлку, @app.get("/items/{item_id}").

  2. Разбор и проверка, а то вдруг хуйню прислали (Parsing & Validation) А вот тут выходит на сцену Pydantic, наш главный зануда и педант, ядрёна вошь! Он берёт все данные — из пути запроса, из этих query-параметров, из заголовков, из тела — и начинает их щупать. «Так-так, — говорит, — тут у нас price должен быть float и больше нуля, а ты мне что подсовываешь, минус один? Да иди ты нахуй!» И если что не так — бац! — цикл прерывается, и клиенту летит ответ 422 Unprocessable Entity с таким подробным описанием ошибки, что хоть плачь. Функция-обработчик даже пальцем не пошевелит, пока Pydantic не скажет «ок».

  3. Впрыскивание зависимостей, или «дай-ка я тебе помогу» (Dependency Injection) Тут FastAPI такой: «О, я вижу, у тебя в аргументах функции есть Depends. Ну-ка, давай выполним всё, что там нужно — проверим авторизацию, подключимся к базе, чаю, блядь, приготовим». И результаты этой всей движухи аккуратно подсовывает в твою функцию. Удобно, сука!

  4. Ну наконец-то, работа! (Path Operation Execution) Вот теперь вызывается твоя родная функция-обработчик. Все данные уже проверены, зависимости готовы — работай, не хочу! И неважно, асинхронная она (async def) или обычная (def) — FastAPI разберётся, куда её затолкать, чтобы не заблокировать главный цикл.

  5. Упаковка и отправка (Response Generation) Функция что-то там посчитала, вернула результат. FastAPI берёт это, сериализует в JSON (чаще всего), красиво упаковывает в HTTP-ответ со статусом, заголовками — и отсылает обратно, как горячую пиццу.

Смотри, вот живой пример, где Pydantic свою власть показывает:

from fastapi import FastAPI
from pydantic import BaseModel, Field

app = FastAPI()

class Item(BaseModel):
    name: str
    price: float = Field(..., gt=0) # Цена, блядь, должна быть больше нуля!

@app.post("/items/")
async def create_item(item: Item):
    # А этот код выполнится ТОЛЬКО если 'item' пройдёт валидацию нашего зануды Pydantic.
    return {"status": "success", "item": item}

Представь, какой-то умник пришлёт {"name": "Apple", "price": -1}. Pydantic посмотрит на это, ебалом заморгает и скажет: «Цена больше нуля, мудила, написано же!». И функция create_item даже не проснётся — сразу в ответе будет ошибка 422. Красота, блядь! Всё автоматически, волнение ебать — ноль.