¿Que es FastAPI?
FastAPI es un framework web moderno y rapido (alto rendimiento) para construir APIs con Python 3.7+ basado en anotaciones de tipo estandar de Python. Es uno de los frameworks de Python mas rapidos disponibles, a la par de NodeJS y Go. FastAPI te da documentacion interactiva automatica de la API, validacion de datos, serializacion y soporte async listos para usar.
¿Por que FastAPI?
- Rapido: Muy alto rendimiento gracias a Starlette y Pydantic
- Type-safe: Usa anotaciones de tipo de Python para validacion, serializacion y documentacion
- Documentacion automatica: Swagger UI y ReDoc generados automaticamente
- Async nativo: Soporte completo para async/await
- Basado en estandares: Construido sobre OpenAPI y JSON Schema
Primeros pasos
# Install FastAPI and Uvicorn (ASGI server)
# pip install fastapi uvicorn[standard]
# main.py - Hello World
from fastapi import FastAPI
app = FastAPI(
title="My API",
description="A demo FastAPI application",
version="1.0.0",
)
@app.get("/")
async def root():
return {"message": "Hello, World!"}
@app.get("/health")
async def health_check():
return {"status": "healthy"}
# Run with: uvicorn main:app --reload
# API docs at: http://localhost:8000/docs (Swagger)
# Alt docs at: http://localhost:8000/redoc
Parametros de ruta y consulta
from fastapi import FastAPI, Query, Path
app = FastAPI()
# Path parameters
@app.get("/users/{user_id}")
async def get_user(user_id: int):
return {"user_id": user_id}
# Path parameter validation
@app.get("/items/{item_id}")
async def get_item(
item_id: int = Path(..., title="Item ID", ge=1, le=1000)
):
return {"item_id": item_id}
# Query parameters
@app.get("/items")
async def list_items(
skip: int = Query(default=0, ge=0),
limit: int = Query(default=10, ge=1, le=100),
search: str | None = Query(default=None, min_length=1, max_length=50),
):
return {
"skip": skip,
"limit": limit,
"search": search,
}
# GET /items?skip=0&limit=20&search=laptop
# Enum path parameters
from enum import Enum
class ModelName(str, Enum):
alexnet = "alexnet"
resnet = "resnet"
lenet = "lenet"
@app.get("/models/{model_name}")
async def get_model(model_name: ModelName):
return {"model": model_name, "message": f"Using {model_name.value}"}
Cuerpo de la solicitud con Pydantic
from pydantic import BaseModel, EmailStr, Field
from datetime import datetime
# Define request/response models
class UserCreate(BaseModel):
name: str = Field(..., min_length=1, max_length=100)
email: EmailStr
age: int = Field(..., ge=0, le=150)
bio: str | None = None
class UserResponse(BaseModel):
id: int
name: str
email: str
age: int
bio: str | None
created_at: datetime
model_config = {"from_attributes": True}
# Use models in endpoints
@app.post("/users", response_model=UserResponse, status_code=201)
async def create_user(user: UserCreate):
# FastAPI automatically:
# 1. Parses the JSON body
# 2. Validates against the Pydantic model
# 3. Returns 422 with details if validation fails
new_user = {
"id": 1,
"name": user.name,
"email": user.email,
"age": user.age,
"bio": user.bio,
"created_at": datetime.now(),
}
return new_user
# Nested models
class Address(BaseModel):
street: str
city: str
country: str
zip_code: str
class UserWithAddress(BaseModel):
name: str
email: EmailStr
address: Address
tags: list[str] = []
@app.post("/users/full")
async def create_full_user(user: UserWithAddress):
return user
Inyeccion de dependencias
from fastapi import FastAPI, Depends, HTTPException, Header
app = FastAPI()
# Simple dependency
async def get_db():
db = {"connection": "active"} # Simulated DB connection
try:
yield db
finally:
pass # Close connection here
# Auth dependency
async def verify_token(authorization: str = Header(...)):
if not authorization.startswith("Bearer "):
raise HTTPException(status_code=401, detail="Invalid token format")
token = authorization.replace("Bearer ", "")
if token != "secret-token":
raise HTTPException(status_code=401, detail="Invalid token")
return {"user_id": 1, "role": "admin"}
# Use dependencies in endpoints
@app.get("/protected")
async def protected_route(
user: dict = Depends(verify_token),
db: dict = Depends(get_db),
):
return {"message": f"Hello user {user['user_id']}", "db": db}
# Reusable dependency classes
class Pagination:
def __init__(self, skip: int = 0, limit: int = 10):
self.skip = skip
self.limit = limit
@app.get("/posts")
async def list_posts(pagination: Pagination = Depends()):
return {"skip": pagination.skip, "limit": pagination.limit}
Puntos clave
- Las anotaciones de tipo impulsan todo: Validacion, documentacion y serializacion desde los tipos
- Modelos Pydantic: Define los contratos de tu API como clases Python
- Inyeccion de dependencias: Dependencias limpias, reutilizables y testeables
- Documentacion automatica: Swagger UI en /docs, ReDoc en /redoc