Знакомство с фреймворком, история развития, ключевые особенности архитектуры, сравнение с FastAPI и другими ASGI-фреймворками
Современный ASGI-фреймворк, созданный для производительности, типизации и модульности
Starlite — это современный ASGI-фреймворк для Python, разработанный с акцентом на:
В 2023 году проект был переименован в Litestar из-за конфликта торговых марок. В этом курсе мы используем название Starlite, но весь код совместим с Litestar.
Starlite появился как ответ на ограничения существующих фреймворков:
| Фреймворк | Год | Особенности | Ограничения |
|---|---|---|---|
| Flask | 2010 | Простота, экосистема | Синхронный (WSGI), нет встроенной типизации |
| Django | 2005 | «Batteries included», ORM | Монолитный, сложность для микросервисов |
| FastAPI | 2018 | Автодокументация, Pydantic | Магия через декораторы, ограничения DI |
| Starlite | 2022 | Явная архитектура, гибкость | Меньшая популярность |

Application — корневой объект приложения:
from starlite import Starlite, get
@get("/hello")
def hello() -> str:
return "Hello, World!"
app = Starlite(route_handlers=[hello])Controller — класс для группировки маршрутов:
from starlite import Controller, get, post
class UserController(Controller):
path = "/users"
@get()
def list_users(self) -> list[User]:
...
@post()
def create_user(self, data: UserCreate) -> User:
...Route Handler — функция или метод, обрабатывающий запрос:
@get("/users/{user_id:int}", status_code=200)
async def get_user(self, user_id: int) -> User:
return await db.get_user(user_id)Для разработчиков FastAPI важно понимать ключевые отличия:
FastAPI:
from fastapi import FastAPI
app = FastAPI()
@app.get("/items")
def get_items():
...Starlite:
from starlite import Starlite, get
@get("/items")
def get_items():
...
app = Starlite(route_handlers=[get_items])Ключевое отличие: в Starlite приложение создаётся отдельно от декораторов. Это даёт больше гибкости при модульной организации кода.
FastAPI:
from fastapi import Depends
def get_db():
...
@app.get("/users")
def get_users(db = Depends(get_db)):
...Starlite:
from starlite import get, Provide
async def get_db():
...
@get("/users", dependencies={"db": Provide(get_db)})
def get_users(db: DB):
...Преимущество Starlite: DI-система более явная и гибкая, поддерживает scopes (app, request, router).
Оба фреймворка используют Pydantic, но с разными подходами:
FastAPI:
@app.post("/users")
def create_user(user: UserCreate):
...Starlite:
@post("/users")
def create_user(data: UserCreate) -> User:
...В Starlite аннотация
data:явно указывает на тело запроса.
FastAPI:
from fastapi import HTTPException
@app.get("/items/{item_id}")
def get_item(item_id: int):
if not item:
raise HTTPException(status_code=404, detail="Item not found")Starlite:
from starlite import NotFoundException
@get("/items/{item_id:int}")
def get_item(item_id: int) -> Item:
if not item:
raise NotFoundException(detail="Item not found")Преимущество Starlite: специализированные классы исключений для каждого HTTP-статуса.
Starlite показывает результаты, сравнимые с FastAPI, а в некоторых сценариях превосходит его:
| Метрика | FastAPI | Starlite |
|---|---|---|
| RPS (простой endpoint) | ~20,000 | ~22,000 |
| RPS (с Pydantic валидацией) | ~15,000 | ~16,500 |
| Время запуска | ~0.3s | ~0.2s |
| Потребление памяти | ~50MB | ~45MB |
Тесты проведены на Uvicorn с uvloop, 10k запросов, wrk benchmark.
Создадим простое приложение:
# main.py
from starlite import Starlite, get, Controller
@get("/health")
def health_check() -> dict[str, str]:
return {"status": "ok"}
class ItemController(Controller):
path = "/items"
@get()
def list_items(self) -> list[str]:
return ["item1", "item2"]
@get("/{item_id:int}")
def get_item(self, item_id: int) -> dict[str, int]:
return {"id": item_id}
app = Starlite(
route_handlers=[health_check, ItemController],
debug=True,
)Запуск:
uvicorn main:app --reloadДоступные эндпоинты:
GET /health — проверка здоровьяGET /items — список элементовGET /items/123 — конкретный элементGET /schema — OpenAPI документацияStarlite полностью поддерживает type hints:
from starlite import get
from pydantic import BaseModel
class User(BaseModel):
id: int
name: str
email: str
@get("/users/{user_id:int}", sync_to_thread=False)
def get_user(user_id: int) -> User:
return User(id=user_id, name="John", email="john@example.com")Проверка типов:
mypy main.py
# Success: no errors foundStarlite предлагает:
В следующих темах мы подробно изучим каждый аспект фреймворка.
Вопросы ещё не добавлены
Вопросы для этой подтемы ещё не добавлены.