SlowAPI: Biblioteca Ligera para Limitación de Velocidad en Starlette y FastAPI - Análisis Detallado
Visión General del Proyecto
SlowAPI constituye una biblioteca especializada en mecanismos de limitación de velocidad, diseñada específicamente para los frameworks Starlette y FastAPI. Inspirada en el reconocido proyecto Flask-Limiter, esta solución ligera facilita a los desarrolladores la implementación de controles de frecuencia en las solicitudes API, protegiendo así los servicios de posibles abusos o sobrecargas.
Características Principales
- Reglas de limitación flexibles: Permite establecer restricciones de solicitud basadas en unidades de tiempo como minutos, horas o días
- Múltiples backends de almacenamiento: Ofrece soporte para Redis, Memcached y almacenamiento en memoria
- Compatibilidad con modos síncrono y asíncrono: Funciona tanto con endpoints HTTP síncronos como asíncronos
- Límites compartidos entre rutas: Posibilidad de configurar reglas de limitación comunes entre diferentes endpoints
- Límites globales predeterminados: Capacidad de establecer restricciones por defecto para todas las rutas
- Cálculo personalizado de costos: Permite definir valores de costo personalizados según la lógica de negocio
Guía de Inicio Rápido
Instalación
La instalación se realiza de manera sencilla mediante el gestor de paquetes pip:
pip install slowapi
Ejemplo de Integración con Starlette
from starlette.applications import Starlette
from starlette.responses import JSONResponse
from starlette.requests import Request
from slowapi import Limiter, _rate_limit_exceeded_handler
from slowapi.util import get_remote_address
from slowapi.errors import RateLimitExceeded
# Configuración del limitador
restriccion = Limiter(key_func=get_remote_address)
aplicacion = Starlette()
aplicacion.state.limiter = restriccion
aplicacion.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
@restriccion.limit("10/minute")
async def ruta_principal(peticion: Request):
return JSONResponse({"mensaje": "Bienvenido a nuestra API"})
aplicacion.add_route("/inicio", ruta_principal)
Este fragmento crea una aplicación Starlettte donde la ruta /inicio acepta un máximo de 10 solicitudes por minuto, devolviendo un código de estado 429 cuando se supera el límite.
Ejemplo de Integración con FastAPI
from fastapi import FastAPI, Request, Response
from slowapi import Limiter, _rate_limit_exceeded_handler
from slowapi.util import get_remote_address
from slowapi.errors import RateLimitExceeded
# Inicialización del limitador
controlador = Limiter(key_func=get_remote_address)
aplicacion = FastAPI()
aplicacion.state.limiter = controlador
aplicacion.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
@app.get("/bienvenido")
@controlador.limit("15/minute")
async def pagina_inicio(peticion: Request):
return Response("Acceso concedido")
@app.get("/planetas")
@controlador.limit("20/hour")
async def ruta_planetas(peticion: Request, respuesta: Response):
return {"planeta": "Marte", "caracteristica": "Planeta rojo"}
Consideraciones de Uso
1. Parámetro de Solicitud Obligatorio
El parámetro request debe pasarse explícitamente a la función del endpoint:
# Implementación correcta
@restriccion.limit("5/minute")
async def mi_endpoint(peticion: Request):
return "Operación completada"
# Implementación incorrecta (no funcionará)
@restriccion.limit("5/minute")
async def mi_endpoint():
return "Esta implementación fallará"
2. Manejo de Tipos de Respuesta
Si es necesario modificar las cabeceras de respuesta (headers_enabled=True), debe proporcionarse explícitamente el objeto resposne:
@restriccion.limit("5/minute")
async def mi_endpoint(peticion: Request, respuesta: Response):
return {"resultado": "Proceso exitoso"}
3. Orden de los Decoradores
El orden de los decoradores es crucial; el decorador limit debe estar debajo del decorador de ruta:
# Orden correcto de decoradores
@router.get("/prueba")
@restriccion.limit("2/minute")
async def funcion_prueba(peticion: Request):
return "Respuesta exitosa"
# Orden incorrecto (no funcionará)
@restriccion.limit("2/minute")
@router.get("/prueba")
async def funcion_prueba(peticion: Request):
return "Esta implementación no funcionará"
4. Limitación para WebSockets
La versión actual no ofrece soporte para la limitación de velocidad en endpoints WebSocket.
Principios de Implementación Técnica
En su implementación interna, SlowAPI utiliza la biblioteca limits para el algoritmo de limitación de velocidad real. El flujo de trabajo fundamental incluye:
- Identificación del cliente mediante key_func (por defecto utiliza la dirección IP remota)
- Verificación de si la solicitud actual excede los límites configurados
- En caso de superación, lanzamiento de la excepción RateLimitExceeded
- El manejador de excepciones convierte la excepción en una respuesta con código 429
Casos de Aplicación
SlowAPI resulta especialmente adecuada para los siguientes escenarios:
- Servicios API públicos que requieren protección contra abusos
- Protección de operaciones sensibles frente a ataques maliciosos
- Garantizar una distribución justa de los recursos del servidor
- Cumplimiento de cuotas de llamada para APIs comerciales
Consideraciones de Rendimiento
Al utilizar el backend de almacenamiento en memoria, el impacto en el rendimietno de SlowAPI es mínimo. Para entornos desplegados de forma distribuida, se recomienda emplear backends Redis o Memcached, los cuales, aunque introducen una ligera latencia de red, garantizan contadores precisos a nivel de clúster.
Conclusión
SlowAPI ofrece a las aplicaciones basadas en Starlette y FastAPI funcionalidades de limitación de velocidad simples pero potentes. Aunque actualmente se encuentra en fase alpha, su diseño de API claro y sus diversas características ya satisfacen las necesidades de la mayoría de los escenarios de aplicación. Los desarrolladores pueden integrarla fácilmente en proyectos existentes, protegiendo eficazmente los recursos API contra un uso excesivo.