FastAPI

Framework API Python moderno - type hints se convierten en docs y validacion, async-nativo, tan rapido como Node/Go

TL;DR

En una línea: FastAPI es la respuesta de Python para crear APIs rápido - los type hints se convierten en docs, validación y velocidad.

Fortalezas principales:

  • Docs auto-generadas - Swagger UI y ReDoc gratis
  • Orientado a tipos - validación Pydantic desde type hints
  • Async nativo - construido sobre Starlette, tan rápido como Node/Go
  • Amigable para desarrolladores - excelente soporte de editor y mensajes de error

Core Concepts

Concept 1: Type Hints = Validation + Docs

Tus type hints se convierten automáticamente en validación de requests, documentación de API y autocompletado del editor.

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class User(BaseModel):
    name: str
    email: str
    age: int | None = None

@app.post("/users/")
def create_user(user: User):  # Validado automáticamente
    return user  # Serializado automáticamente

Concept 2: Path Operations

Los decoradores definen tus endpoints HTTP:

@app.get("/users/{user_id}")    # GET con parámetro de ruta
@app.post("/users/")            # POST
@app.put("/users/{user_id}")    # PUT
@app.delete("/users/{user_id}") # DELETE

Concept 3: Dependency Injection

Dependencias reutilizables para auth, conexiones de base de datos, etc.

from fastapi import Depends

def get_current_user(token: str = Header()):
    return decode_token(token)

@app.get("/me")
def read_me(user = Depends(get_current_user)):
    return user

Quick Start

Install

pip install "fastapi[standard]"

Create main.py

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def root():
    return {"message": "¡Hola FastAPI!"}

@app.get("/items/{item_id}")
def read_item(item_id: int, q: str | None = None):
    return {"item_id": item_id, "q": q}

Run

fastapi dev main.py
# Abre http://localhost:8000
# Docs en http://localhost:8000/docs

Gotchas

Route order matters

# ❌ Mal - /users/me nunca se alcanza
@app.get("/users/{user_id}")
def get_user(user_id: str): ...

@app.get("/users/me")  # ¡Nunca se alcanza!
def get_me(): ...

# ✅ Correcto - rutas específicas primero
@app.get("/users/me")
def get_me(): ...

@app.get("/users/{user_id}")
def get_user(user_id: str): ...

Async vs sync functions

# Usa async para operaciones I/O
@app.get("/async")
async def async_endpoint():
    data = await fetch_from_db()  # No bloqueante
    return data

# Usa sync para llamadas CPU-bound o bloqueantes
@app.get("/sync")
def sync_endpoint():
    return heavy_computation()  # Se ejecuta en threadpool

Request body needs Pydantic model

from pydantic import BaseModel

class Item(BaseModel):
    name: str
    price: float
    description: str | None = None

@app.post("/items/")
def create_item(item: Item):  # El body se valida
    return item

# Para acceso al body crudo
from fastapi import Request
@app.post("/raw")
async def raw_body(request: Request):
    body = await request.body()

Query params vs path params

# Parámetro de ruta: parte de la URL, requerido
@app.get("/users/{user_id}")  # /users/123
def get_user(user_id: int): ...

# Parámetro de query: después de ?, opcional por defecto
@app.get("/items/")  # /items/?skip=0&limit=10
def get_items(skip: int = 0, limit: int = 10): ...

When to Use

Ideal para:

  • APIs REST y microservicios
  • Serving de modelos ML
  • Aplicaciones en tiempo real (WebSockets)
  • Equipos que aman la seguridad de tipos

No ideal para:

  • Apps full-stack con templates (usa Django)
  • Scripts simples (excesivo)
  • Proyectos Python 2 legacy

Comparación:

CaracterísticaFastAPIDjangoFlask
VelocidadMuy rápidaMediaMedia
AsyncNativoLimitadoLimitado
Auto docsNoNo
Curva de aprendizajeFácilMediaFácil

Next Steps

Cheatsheet

PatrónCódigo
Parámetro de ruta@app.get("/items/{id}")
Parámetro de querydef f(skip: int = 0)
Cuerpo de requestdef f(item: Item)
Headerdef f(token: str = Header())
Cookiedef f(session: str = Cookie())
Modelo de respuesta@app.get("/", response_model=Item)
Código de estado@app.post("/", status_code=201)
Dependenciadef f(db = Depends(get_db))
Tarea en segundo planobackground_tasks.add_task(fn, arg)