TechLead
Lección 14 de 25
5 min de lectura
Python

Fundamentos de FastAPI

Construye APIs modernas y de alto rendimiento con FastAPI, documentacion automatica y soporte async

¿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

Continuar Aprendiendo