Как реализовать ограничение частоты запросов (rate limiting) в FastAPI

Ответ

В FastAPI нет встроенного механизма для ограничения частоты запросов, но его легко интегрировать с помощью сторонних библиотек. Самым популярным решением является fastapi-limiter.

Зачем это нужно?

  • Защита от DoS-атак: Предотвращает перегрузку сервера большим количеством запросов.
  • Стабильность сервиса: Обеспечивает справедливое распределение ресурсов между пользователями.
  • Контроль доступа к API: Позволяет устанавливать разные лимиты для разных тарифных планов.

Принцип работы:

Библиотека использует хранилище (обычно Redis) для отслеживания количества запросов от каждого клиента (например, по IP-адресу) за определенный промежуток времени.

Пример с fastapi-limiter:

  1. Установка библиотек:

    pip install fastapi-limiter uvicorn redis
  2. Реализация в коде:

    from fastapi import FastAPI, Depends, Request
    from fastapi_limiter import FastAPILimiter
    from fastapi_limiter.depends import RateLimiter
    import redis.asyncio as redis
    
    app = FastAPI()
    
    @app.on_event("startup")
    async def startup():
        # Инициализация подключения к Redis
        redis_connection = redis.from_url("redis://localhost:6379", encoding="utf-8", decode_responses=True)
        await FastAPILimiter.init(redis_connection)
    
    # Применение лимита к конкретному эндпоинту
    @app.get("/limited", dependencies=[Depends(RateLimiter(times=2, seconds=5))])
    async def limited_route():
        return {"message": "Этот эндпоинт ограничен 2 запросами в 5 секунд."}
    
    # Глобальное применение лимита ко всем эндпоинтам
    @app.get("/global")
    async def global_route(request: Request):
        # Идентификатор может быть IP-адресом, токеном пользователя и т.д.
        identifier = request.client.host 
        return {"message": "Этот эндпоинт использует глобальный лимит."}

В этом примере эндпоинт /limited будет возвращать ошибку 429 Too Many Requests, если клиент сделает более 2 запросов за 5 секунд.