Первое приложение и запуск через uvicorn
Минимальное FastAPI-приложение — это объект FastAPI(), к которому через декораторы привязаны функции-обработчики, запущенный ASGI-сервером uvicorn.
Три кирпича любого приложения: экземпляр
app = FastAPI(), декоратор маршрута вроде@app.get("/")и ASGI-сервер uvicorn, который принимает реальные HTTP-соединения.
Давайте соберём первое приложение и поймём, что делает каждая строка. FastAPI сам по себе не открывает сетевой порт — он лишь описывает, как обрабатывать запросы. Принимать соединения должен ASGI-сервер; стандартный выбор — uvicorn. Он слушает порт, получает сырой HTTP, превращает его в ASGI-события и передаёт вашему app.
Вот канонический пример. Поскольку это код FastAPI, он показан как обычный текст:
from fastapi import FastAPI
app = FastAPI(title="Моё первое API")
@app.get("/")
async def root():
return {"message": "Привет, FastAPI"}
@app.get("/ping")
async def ping():
return {"status": "ok"}
Запускаем сервер командой. Современный способ — встроенный CLI fastapi, классический — напрямую uvicorn:
fastapi dev main.py
uvicorn main:app --reload
Здесь main — имя файла без .py, app — имя переменной с приложением. Флаг --reload перезапускает сервер при изменении кода (только для разработки). После запуска FastAPI бесплатно отдаёт интерактивную документацию по адресу /docs (Swagger UI) и /redoc.
Как работает под капотом
Декоратор @app.get("/ping") не вызывает функцию — он регистрирует её в таблице маршрутов приложения, связывая пару «метод + путь» с обработчиком и его сигнатурой. Когда придёт запрос, Starlette найдёт совпадение в этой таблице. Концептуально таблица маршрутов — это просто словарь. Смоделируем мини-роутер на stdlib:
routes = {}
def get(path):
def decorator(func):
routes[("GET", path)] = func # регистрация, как делает @app.get
return func
return decorator
@get("/")
def root():
return {"message": "Привет"}
@get("/ping")
def ping():
return {"status": "ok"}
def handle(method, path):
handler = routes.get((method, path))
if handler is None:
return 404, {"detail": "Not Found"}
return 200, handler()
print(handle("GET", "/"))
print(handle("GET", "/ping"))
print(handle("GET", "/missing"))
Попробуй сам ▶ Так же FastAPI ищет обработчик: совпало — вызывает, не совпало — отдаёт 404.
А что значит «вернуть словарь»? FastAPI берёт результат функции и сериализует его в JSON, проставляя заголовок Content-Type: application/json. Это та же логика, что и стандартный json.dumps:
import json
result = {"message": "Привет, FastAPI", "items": [1, 2, 3]}
body = json.dumps(result, ensure_ascii=False)
print("тело ответа:", body)
print("длина в байтах:", len(body.encode("utf-8")))
Попробуй сам ▶ Возврат словаря из обработчика — это, по сути, json.dumps под капотом.
Частые ошибки
Типичная путаница новичков: в команде запуска перепутать имя файла и имя переменной (main:app — это файл:переменная, а не наоборот). Ещё одна — оставить --reload в продакшене, где он не нужен и ест ресурсы. Третья — пытаться «запустить FastAPI» без сервера: сам по себе модуль ничего не слушает, нужен uvicorn или CLI.
Best practices
- Давайте приложению осмысленные
title,version,description— они попадут в/docs. - В разработке используйте
fastapi devилиuvicorn --reload; в проде —fastapi runили uvicorn под управлением gunicorn/процесс-менеджера. - Сразу открывайте
/docs— это лучший способ проверить и продемонстрировать API.
ASGI против WSGI — почему это важно
FastAPI работает поверх ASGI, а не классического WSGI, и это не формальность. WSGI — старый синхронный стандарт связи между веб-сервером и Python-приложением: один запрос — один поток, который занят целиком до ответа. ASGI — его асинхронный наследник: он умеет приостанавливать обработку в точках ожидания и обслуживать тысячи соединений малым числом потоков, а заодно поддерживает веб-сокеты и события жизненного цикла. Именно поэтому FastAPI нельзя запустить под обычным WSGI-сервером вроде классического gunicorn без ASGI-воркера — нужен uvicorn (или gunicorn с UvicornWorker). Понимание этого слоя объясняет, почему «просто запустить файл» недостаточно: приложение лишь описывает обработку в терминах ASGI-событий, а превращать реальные TCP-соединения в эти события должен ASGI-сервер.
Итог: приложение — это FastAPI() плюс зарегистрированные декораторами маршруты, запущенное ASGI-сервером. Декоратор только регистрирует функцию, а возврат словаря превращается в JSON-ответ.