Создание приложения, первый эндпоинт, запуск с Uvicorn
В этой теме вы создадите своё первое FastAPI-приложение, запустите его и разберётесь, как работает каждый компонент.
Создайте файл main.py:
from fastapi import FastAPI
app = FastAPI()
@app.get('/')
def read_root():
return {'Hello': 'World'}Это всё, что нужно для работающего API. Разберём по строкам.
from fastapi import FastAPIИмпортируем класс FastAPI — это основа вашего приложения. Он создаёт экземпляр приложения и хранит всю информацию о маршрутах, зависимостях, middleware.
app = FastAPI()Создаём экземпляр приложения. Теперь app знает о всех ваших декораторах @app.get(), @app.post() и т.д.
Можно передать дополнительные параметры:
app = FastAPI(
title="My API",
description="Моё первое API для обучения",
version="1.0.0",
docs_url="/docs", # Путь к Swagger UI
redoc_url="/redoc", # Путь к ReDoc
openapi_url="/openapi.json" # Путь к OpenAPI схеме
)Эти параметры отобразятся в документации.
@app.get('/')
def read_root():
return {'Hello': 'World'}Декоратор @app.get('/'):
/, вызови функцию read_root»Функция read_root():
read_root, create_user, get_items)uvicorn main:app --reloadРазберём команду:
| Часть | Значение |
|---|---|
uvicorn | ASGI-сервер для запуска |
main | Имя файла без .py (main.py) |
app | Имя переменной приложения |
--reload | Автоперезагрузка при изменении кода |
После запуска вы увидите:
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO: Started reloader process [28949] using WatchFiles
INFO: Started server process [28951]
INFO: Waiting for application startup.
INFO: Application startup complete.
import uvicorn
from main import app
if __name__ == '__main__':
uvicorn.run(app, host='0.0.0.0', port=8000, reload=True)Этот способ удобен, если нужно запустить сервер из кода (например, в тестах).
Откройте http://localhost:8000 — вы увидите:
{"Hello": "World"}curl http://localhost:8000Ответ:
{"Hello": "World"}Откройте http://localhost:8000/docs — Swagger UI:
GET /Когда вы делаете запрос GET /, происходит следующее:
1. Браузер → HTTP GET http://localhost:8000/
↓
2. Uvicorn (ASGI-сервер) принимает соединение
↓
3. Uvicorn → FastAPI app (ASGI-протокол)
↓
4. FastAPI ищет маршрут: GET /
↓
5. Находит функцию read_root()
↓
6. Вызывает read_root()
↓
7. Получает ответ: {'Hello': 'World'}
↓
8. Сериализует в JSON: {"Hello": "World"}
↓
9. Uvicorn → Браузер (HTTP 200 OK)
Весь этот процесс занимает менее 1 миллисекунды для простого эндпоинта.
FastAPI поддерживает все стандартные HTTP-методы:
from fastapi import FastAPI
app = FastAPI()
@app.get('/items')
def get_items():
"""Получить список элементов (чтение)"""
return [{'id': 1, 'name': 'Item 1'}]
@app.post('/items')
def create_item():
"""Создать новый элемент (создание)"""
return {'id': 2, 'name': 'New Item'}
@app.put('/items/1')
def update_item():
"""Обновить существующий элемент (полное обновление)"""
return {'id': 1, 'name': 'Updated Item'}
@app.patch('/items/1')
def patch_item():
"""Частичное обновление элемента"""
return {'id': 1, 'name': 'Patched Item'}
@app.delete('/items/1')
def delete_item():
"""Удалить элемент"""
return {'deleted': True}| Метод | Назначение | Идемпотентность |
|---|---|---|
GET | Получение данных | Да (можно вызывать многократно) |
POST | Создание ресурса | Нет (создаст несколько копий) |
PUT | Полное обновление | Да (результат одинаковый) |
PATCH | Частичное обновление | Нет (зависит от данных) |
DELETE | Удаление | Да (ресурс уже удалён) |
Идемпотентность — свойство операции: многократное выполнение даёт тот же результат, что и однократное.
FastAPI автоматически возвращает правильные статус-коды:
200 OK — успешный GET, PUT, PATCH201 Created — успешный POST (нужно указать явно)204 No Content — успешный DELETE (нужно указать явно)422 Unprocessable Entity — ошибка валидации404 Not Found — маршрут не найден500 Internal Server Error — исключение в кодеfrom fastapi import FastAPI, status
app = FastAPI()
@app.post('/items', status_code=status.HTTP_201_CREATED)
def create_item():
return {'id': 1, 'name': 'Item'}Или через декоратор:
@app.post('/items', status_code=201)
def create_item():
return {'id': 1, 'name': 'Item'}from fastapi import FastAPI, status
from fastapi.responses import Response
app = FastAPI()
@app.delete('/items/{item_id}', status_code=status.HTTP_204_NO_CONTENT)
def delete_item(item_id: int):
# Ничего не возвращаем
return Response(status_code=status.HTTP_204_NO_CONTENT)Добавим параметры в наш эндпоинт:
@app.get('/items/{item_id}')
def get_item(item_id: int):
return {'item_id': item_id}Теперь при запросе /items/5 вы получите:
{"item_id": 5}Важно: FastAPI автоматически преобразует item_id из строки в int. Если вы отправите /items/abc, получите ошибку 422:
{
"detail": [
{
"type": "int_parsing",
"loc": ["path", "item_id"],
"msg": "Input should be a valid integer",
"input": "abc"
}
]
}Это автоматическая валидация — одна из ключевых фич FastAPI.
@app.get('/items')
def get_items(skip: int = 0, limit: int = 10):
return {'skip': skip, 'limit': limit}Запрос /items?skip=20&limit=5 вернёт:
{"skip": 20, "limit": 5}Query-параметры указываются после ? в URL через &.
Откройте http://localhost:8000/docs. Вы увидите:
Нажмите на GET /items/{item_id} → Try it out → Введите item_id: 42 → Execute.
Вы увидите:
http://localhost:8000/items/42{"item_id": 42}200 OKОткройте http://localhost:8000/redoc.
ReDoc — это более строгая, трёхколоночная документация:
ReDoc лучше подходит для печати и чтения, Swagger UI — для интерактивного тестирования.
FastAPI генерирует полную спецификацию API в формате OpenAPI 3.0.
Откройте http://localhost:8000/openapi.json:
{
"openapi": "3.1.0",
"info": {
"title": "My API",
"version": "1.0.0"
},
"paths": {
"/": {
"get": {
"summary": "Read Root",
"operationId": "read_root__get",
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"Hello": {"type": "string"}
}
}
}
}
}
}
}
}
}
}Эта схема используется:
Uvicorn выводит логи в консоль:
INFO: 127.0.0.1:54321 - "GET / HTTP/1.1" 200 OK
INFO: 127.0.0.1:54322 - "GET /items HTTP/1.1" 200 OK
INFO: 127.0.0.1:54323 - "GET /items/abc HTTP/1.1" 422 Unprocessable Entity
Формат: IP:PORT - "METHOD PATH HTTP/VERSION" STATUS_CODE
Для подробных логов используйте --log-level debug:
uvicorn main:app --reload --log-level debugТеперь вы увидите детали обработки каждого запроса.
--reloaduvicorn main:appПроблема: При изменении кода сервер не перезагружается. Нужно останавливать (Ctrl+C) и запускать заново.
Решение: Добавьте --reload для разработки.
uvicorn app:app --reloadПроблема: Файл называется main.py, а не app.py.
Решение: Укажите правильное имя: uvicorn main:app.
@app.get('/slow')
def slow_endpoint():
time.sleep(5) # Блокирует все запросы!
return {'done': True}Проблема: time.sleep() блокирует event loop. Пока один запрос ждёт, другие не обрабатываются.
Решение: Используйте async def и await asyncio.sleep():
import asyncio
@app.get('/slow')
async def slow_endpoint():
await asyncio.sleep(5) # Не блокирует
return {'done': True}@app.get('/nothing')
def nothing():
pass # Возвращает NoneПроблема: FastAPI вернёт пустое тело с 200 OK, но это может сбить с толку клиентов.
Решение: Явно верните пустой ответ:
from fastapi import Response
@app.get('/nothing')
def nothing():
return Response(status_code=204)В следующей теме вы изучите параметры пути глубже:
Path()Вопросы ещё не добавлены
Вопросы для этой подтемы ещё не добавлены.