Appearance
FastAPI
APIs agiles con Python y FastAPI
FastAPI fue construido por el desarrollador colombiano Sebastián Ramirez, se trata de un marco de trabajo web moderno y de alto rendimiento para construir APIs con Python 3.7+ basado en type hints estándar. Se destaca por su velocidad, facilidad de uso y generación automática de documentación.
Lo que hace atractivo este framework para el desrrallo de una API bajo Python son caractarísticas tales como:
- Validación automática: Usa type hints de Python para validar datos de entrada y salida
- Documentación automática: Genera OpenAPI (Swagger) y ReDoc sin configuración adicional
- Alto rendimiento: Basado en Starlette y Pydantic, comparable a NodeJS y Go
- Soporte async/await: Programación asíncrona nativa para operaciones I/O
- Inyección de dependencias: Sistema integrado para gestionar dependencias
Instalación de FastAPI
bash
pip install fastapi
pip install uvicorn[standard]Uvicorn es el servidor ASGI recomendado para ejecutar FastAPI en producción.
Es conveniente usar entornos virtuales para instalación, por ejemplo, si usas sistema macOS.
Primera API con FastAPI
Crea un archivo main.py:
python
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"Hello": "World"}
@app.get("/items/{item_id}")
def read_item(item_id: int, q: str = None):
return {"item_id": item_id, "q": q}Ejecuta el servidor:
bash
uvicorn main:app --reloadLa API estará disponible en
http://127.0.0.1:8000La documentación automática se genera enhttp://127.0.0.1:8000/docs(Swagger UI) o/redoc(ReDoc)
Estructura de proyecto recomendada
myapi/
├── app/
│ ├── __init__.py
│ ├── main.py # Punto de entrada de la aplicación
│ ├── models.py # Modelos Pydantic (esquemas de datos)
│ ├── routers/ # Rutas organizadas por recurso
│ │ ├── __init__.py
│ │ ├── items.py
│ │ └── users.py
│ ├── dependencies.py # Dependencias inyectables
│ └── database.py # Configuración de base de datos
├── requirements.txt
└── .envConceptos clave
Path Operations (Operaciones de ruta)
python
@app.get("/items") # Leer recursos
@app.post("/items") # Crear recursos
@app.put("/items/{id}") # Actualizar completo
@app.patch("/items/{id}") # Actualizar parcial
@app.delete("/items/{id}") # Eliminar recursosModelos con Pydantic
python
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: str = None
price: float
tax: float = None
@app.post("/items/")
def create_item(item: Item):
return itemParámetros de consulta y cuerpo
python
from fastapi import Query, Path, Body
@app.get("/items/")
def read_items(
q: str = Query(None, max_length=50),
skip: int = 0,
limit: int = 100
):
return {"q": q, "skip": skip, "limit": limit}
@app.put("/items/{item_id}")
def update_item(
item_id: int = Path(..., title="ID del item"),
item: Item = Body(...)
):
return {"item_id": item_id, **item.dict()}Inyección de dependencias
python
from fastapi import Depends
def get_query_token(token: str):
if token != "fake-super-secret-token":
raise HTTPException(status_code=403, detail="Token inválido")
return token
@app.get("/items/")
def read_items(token: str = Depends(get_query_token)):
return [{"item": "Foo", "token": token}]Respuestas y status codes
python
from fastapi import Response, status
@app.post("/items/", status_code=status.HTTP_201_CREATED)
def create_item(item: Item, response: Response):
response.headers["X-Custom-Header"] = "custom-value"
return itemMiddleware y CORS
python
from fastapi.middleware.cors import CORSMiddleware
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)Base de datos con SQLAlchemy
python
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
SQLALCHEMY_DATABASE_URL = "sqlite:///./test.db"
engine = create_engine(SQLALCHEMY_DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
# Dependencia para obtener sesión de DB
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()Testing
python
from fastapi.testclient import TestClient
client = TestClient(app)
def test_read_root():
response = client.get("/")
assert response.status_code == 200
assert response.json() == {"Hello": "World"}
def test_read_item():
response = client.get("/items/42?q=test")
assert response.status_code == 200
assert response.json() == {"item_id": 42, "q": "test"}Despliegue
bash
# Desarrollo
uvicorn main:app --reload --host 0.0.0.0 --port 8000
# Producción
uvicorn main:app --host 0.0.0.0 --port 80 --workers 4
# Con Gunicorn (para múltiples workers)
gunicorn main:app -w 4 -k uvicorn.workers.UvicornWorker