Module 6: Project — CRUD API (To-Do List)

Entrega y Evaluación

Descripción

Cierras el Módulo 6 con el código completo del To-Do List API, una rúbrica de evaluación de 100 puntos, errores comunes a evitar, una retrospectiva 4Ls y la conexión con lo que viene después: FastAPI Advanced Features Guide.


Código completo de referencia

El API completo está en la Cápsula 05. A continuación tienes la especificación detallada de lo que debe incluir tu implementación final.

Modelos Pydantic (4 modelos, 18 campos en total)

ModeloCamposDescripción
TaskCreate4 campos: title, description, status, priorityRequest para POST. title con min_length=1, max_length=200. status y priority con Literal.
TaskUpdate4 campos opcionales: title, description, status, priorityRequest para PATCH. Todos Optional.
TaskResponse6 campos: id, title, description, status, priority, created_atResponse en GET, POST, PUT, PATCH. Incluye from_attributes=True.
TaskListResponse4 campos: total, skip, limit, itemsResponse para GET /tasks paginado.

Endpoints disponibles (7 rutas, 8 operaciones)

MétodoRutaStatus codesDescripción
GET/200Info del servicio: service, version, total_tasks
GET/tasks200Lista con status, priority, search, sort_by, order, skip, limit
GET/tasks/{task_id}200, 404Obtener tarea por ID
POST/tasks201, 422Crear tarea
PUT/tasks/{task_id}200, 404, 422Actualizar completa
PATCH/tasks/{task_id}200, 404, 422Actualizar parcial
DELETE/tasks/{task_id}200, 404Eliminar tarea

Exception handlers

HandlerExcepciónFormato de salida
http_exception_handlerHTTPException`{"success": false, "error": {"code": "NOT_FOUND"
validation_exception_handlerRequestValidationErrorIgual que arriba con code "VALIDATION_ERROR", más campo opcional "details" con los errores de Pydantic

CORS

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

Estructura exacta del proyecto

todo-api/
├── venv/
├── app/
│   ├── __init__.py
│   └── main.py          ← ~250-350 líneas
├── requirements.txt    ← fastapi>=0.115.0, uvicorn[standard]>=0.32.0
└── .gitignore          ← venv/, __pycache__/, *.pyc, .env

Funciones auxiliares obligatorias

  • next_id() — Devuelve max(id) + 1
  • find_task(task_id: int) — Devuelve el dict o None
  • _status_to_code(status: int) — Mapea 404→NOT_FOUND, 400→BAD_REQUEST, etc.
  • PRIORITY_ORDER — Dict para ordenar prioridad: high=0, medium=1, low=2

Ejemplo de uso con curl

# Listar tareas
curl http://localhost:8000/tasks

# Filtrar por status
curl "http://localhost:8000/tasks?status=pending"

# Crear tarea
curl -X POST http://localhost:8000/tasks \
  -H "Content-Type: application/json" \
  -d '{"title": "Nueva tarea", "priority": "high"}'

# Actualizar parcial
curl -X PATCH http://localhost:8000/tasks/1 \
  -H "Content-Type: application/json" \
  -d '{"status": "completed"}'

El código fuente completo está en la Cápsula 05. Copia app/main.py de ahí como referencia final.


Autoevaluación guiada

Sigue estos pasos con el servidor corriendo (uvicorn app.main:app --reload). Marca los puntos y suma al final.

Paso 1: Levantar y verificar servicio (base)

  1. Ejecuta uvicorn app.main:app --reload desde la carpeta todo-api con el venv activado.
  2. ¿Arranca sin errores? Si sí, continúa.
  3. Abre http://localhost:8000/ y verifica que recibes JSON con service, version y total_tasks.
  4. Resultado esperado: {"service": "To-Do List API", "version": "1.0.0", "total_tasks": N} con N ≥ 0. Puntos: base para evaluar Funcionalidad.

Paso 2: Funcionalidad — GET / y GET /tasks (12 pts)

AcciónCómo probarResultado esperadopts
GET /curl http://localhost:8000/JSON con service, version, total_tasks6
GET /taskscurl http://localhost:8000/tasks{"total": N, "skip": 0, "limit": 10, "items": [...]}3
Filtroscurl "http://localhost:8000/tasks?status=pending&priority=high&search=API"Lista filtrada correctamente3

Si los tres funcionan: 12 pts.

Paso 3: Funcionalidad — CRUD (18 pts)

AcciónCómo probarResultado esperadopts
POSTPOST /tasks con {"title": "Test"}, verificar 201 y que tenga id y created_at201, body con id y created_at6
GET/PUT/PATCH/DELETECrear tarea 4, luego GET, PUT, PATCH, DELETETodas las operaciones responden correctamente6
PATCH exclude_unsetPATCH con solo {"status": "completed"}Solo status cambia, title/description intactos6

Si todo funciona: 18 pts. Funcionalidad total: 30 pts.

Paso 4: Validación (25 pts)

AcciónCómo probarResultado esperadopts
TaskCreate constraintsPOST con {"title": ""} o {"status": "invalid"}422 con formato success/error/status_code8
TaskUpdate OptionalPATCH con {} o solo {"status": "completed"}No errores, actualización parcial correcta6
Query paramsGET con ?skip=-1 o ?limit=0422 o rechazo de valores inválidos5
Datos inválidos 422Cualquier body mal formadoRespuesta con code VALIDATION_ERROR6

Si cumples lo anterior: 25 pts.

Paso 5: Error handling (20 pts)

AcciónCómo probarResultado esperadopts
404 en GET/PUT/PATCH/DELETEGET /tasks/999, PUT/PATCH/DELETE con id inexistenteJSON con success: false, error.code: "NOT_FOUND"8
Handler HTTPExceptionCualquier 404, 400Formato consistente en todas las respuestas6
Handler RequestValidationErrorPOST con title vacíoFormato con code "VALIDATION_ERROR"6

Si todo tiene formato consistente: 20 pts.

Paso 6: Organización y documentación (25 pts)

CriterioCómo evaluarpts
Código limpioRevisar main.py: sin duplicación, funciones claras5
Modelos bien definidosTaskCreate, TaskUpdate, TaskResponse, TaskListResponse separados5
Funciones auxiliaresnext_id, find_task usadas en los endpoints5
FastAPI metadata/docs muestra title, description, version5
CORS y tagsCORS configurado, tags en endpoints5

Total máximo: 100 pts. Si obtienes 90+, estás en nivel Excelente.

Consejos para la autoevaluación

  • Usa la pestaña "Try it out" de /docs para probar cada endpoint sin instalar curl.
  • Si un criterio falla, anota el número del paso y el resultado real vs esperado; te ayudará a depurar.
  • No te saltes el Paso 5: el formato de error consistente es uno de los diferenciadores más visibles para quien consuma tu API.

Criterios de evaluación detallados

Al evaluar tu proyecto, revisa que cada criterio cumpla lo esperado. La rúbrica suma 100 puntos.


Rúbrica de evaluación (100 puntos)

Funcionalidad (30 pts)

  • (6) GET / retorna info del servicio
  • (6) GET /tasks con filtros (status, priority, search), ordenamiento y paginación
  • (6) GET /tasks/{id}, POST, PUT, PATCH, DELETE funcionan correctamente
  • (6) POST retorna 201 y asigna id y created_at
  • (6) PATCH actualiza solo campos enviados (exclude_unset)

Validación (25 pts)

  • (8) TaskCreate con Field constraints (title min 1, Literal para status/priority)
  • (6) TaskUpdate con campos Optional
  • (6) Datos inválidos retornan 422
  • (5) Query params (skip, limit, sort_by, order) validados

Error handling (20 pts)

  • (8) HTTPException para 404 en todos los endpoints que lo requieren
  • (6) Exception handler para HTTPException con formato consistente
  • (6) Exception handler para RequestValidationError

Organización (15 pts)

  • (5) Código limpio, sin duplicación innecesaria
  • (5) Modelos Pydantic bien definidos y separados
  • (5) Funciones auxiliares (next_id, find_task) usadas correctamente

Documentación (10 pts)

  • (5) FastAPI con title, description, version
  • (5) CORS configurado, tags en endpoints

Guía de puntuación

RangoNivelDescripción
90-100ExcelenteAPI completa, código limpio, sin errores de ejecución
80-89Muy bienCumple todo, pequeños ajustes posibles
70-79BienFuncionalidad completa, mejorar organización o validación
60-69AceptableFunciona pero falta pulido (handlers, CORS, docs)
< 60En progresoRevisar cápsulas anteriores y completar endpoints faltantes

Checklist de entrega

  • Proyecto ejecuta sin errores: uvicorn app.main:app --reload
  • GET / retorna servicio, versión y total_tasks
  • GET /tasks con status, priority, search, sort_by, order, skip, limit
  • GET /tasks/{id} retorna 404 si no existe
  • POST /tasks crea tarea y retorna 201
  • PUT /tasks/{id} actualiza completa preservando created_at
  • PATCH /tasks/{id} actualiza parcial con exclude_unset
  • DELETE /tasks/{id} elimina y retorna confirmación
  • Errores con formato consistente (success, error, status_code)
  • CORS habilitado
  • /docs muestra documentación correcta

Flujo de verificación completo

Ejecuta en orden para validar el CRUD de extremo a extremo. Respuestas esperadas incluidas.

PasoAcciónComando o bodyRespuesta esperada
1GET /curl http://localhost:8000/{"service":"To-Do List API","version":"1.0.0","total_tasks":3}
2GET /taskscurl http://localhost:8000/tasks{"total":3,"skip":0,"limit":10,"items":[{...},{...},{...}]}
3POST /tasksBody: {"title":"Tarea 4","priority":"high"}201, {"id":4,"title":"Tarea 4","description":"","status":"pending","priority":"high","created_at":"..."}
4GET /tasks/4curl http://localhost:8000/tasks/4200, tarea recién creada con id 4
5POST inválidoBody: {"title":""}422, {"success":false,"error":{"code":"VALIDATION_ERROR",...},"status_code":422}
6PUT /tasks/4Body completo: title, description, status, priority200, tarea actualizada, created_at sin cambiar
7PATCH /tasks/4Body: {"status":"completed"}200, tarea con status "completed", resto igual
8GET /tasks/4curl http://localhost:8000/tasks/4200, "status":"completed"
9GET /tasks?status=completedcurl "http://localhost:8000/tasks?status=completed"Lista filtrada con al menos la tarea 4
10DELETE /tasks/4curl -X DELETE http://localhost:8000/tasks/4200, {"message":"Task deleted","id":4}
11GET /tasks/4curl http://localhost:8000/tasks/4404, {"success":false,"error":{"code":"NOT_FOUND",...},"status_code":404}

Si los 11 pasos coinciden con las respuestas esperadas, tu API pasa la verificación completa.


Comparación con APIs profesionales

Lo que esta API tiene ✅

  • CRUD completo con métodos HTTP correctos
  • Validación Pydantic (campos, Literal, constraints)
  • Error handling con formato consistente
  • CORS para consumo desde frontend
  • Documentación automática (/docs, /redoc)
  • Paginación, filtros y ordenamiento en GET /tasks

Esto demuestra que dominas los fundamentos de una API REST moderna.

Lo que falta (y dónde aprenderlo)

AspectoEstado actualGuía o módulo futuro
AutenticaciónNo hay login ni tokensAuthentication & Authorization Guide
Base de datos persistenteSolo en memoriaPostgreSQL & SQLAlchemy Guide
Tests automatizadosNo hay pytestTesting Guide
DespliegueLocal únicamenteDocker, CI/CD guides
Rate limitingNo hay protecciónFastAPI Advanced Features
Logging estructuradoSolo prints/defaultProduction Best Practices

No te preocupes por lo que falta: este proyecto es el punto de partida. Las guías siguientes te llevarán paso a paso a añadir cada capa.

Resumen visual

Tu To-Do API actual     →     API de producción
─────────────────────────────────────────────────
CRUD ✅                      CRUD ✅
Validación ✅                 Validación ✅
Error handling ✅             Error handling ✅
CORS ✅                       CORS ✅
Docs ✅                       Docs ✅
En memoria                    PostgreSQL/SQLAlchemy
Sin auth                      JWT/OAuth2
Sin tests                     pytest + cobertura
Local                         Docker + CI/CD

Errores comunes

PATCH sobrescribe con None

Si usas model_dump() sin exclude_unset=True, los campos no enviados se serializan como None y sobrescriben valores existentes. Siempre usa model_dump(exclude_unset=True) para PATCH.

PUT modifica created_at

En PUT debes preservar created_at del recurso original. No lo reemplaces con datetime.utcnow().

Filtros con valores inválidos

Si status o priority aceptan cualquier string, el filtro puede devolver lista vacía sin avisar. Considera validar con Literal en los query params o documentar los valores válidos claramente.

Ordenamiento por priority sin mapeo

Si ordenas priority como string, "high" < "low" alfabéticamente. Usa un diccionario de orden (PRIORITY_ORDER) para prioridad semántica correcta.

CORS en producción

allow_origins=["*"] es cómodo en desarrollo pero inseguro en producción. Define orígenes concretos cuando despliegues.


Troubleshooting de entrega

requirements.txt faltante o incompleto

Problema: Quien clone tu repo no puede instalar dependencias.
Solución: Crea requirements.txt en la raíz con:

fastapi>=0.115.0
uvicorn[standard]>=0.32.0

Verifica con pip install -r requirements.txt en un venv nuevo antes de subir.

venv incluido en git

Problema: La carpeta venv/ se sube al repositorio y ocupa mucho espacio.
Solución: Añade venv/ a .gitignore. Si ya lo subiste, elimínalo del tracking: git rm -r --cached venv/ y haz commit.

CORS bloqueando tests desde frontend

Problema: Un frontend en localhost:3000 no puede llamar a localhost:8000; el navegador muestra error CORS.
Solución: Confirma que CORSMiddleware está registrado con allow_origins=["*"] (o incluye tu origen). Revisa en DevTools (Network) que la respuesta OPTIONS devuelva 200 y los headers Access-Control-Allow-Origin y Access-Control-Allow-Methods.

Puerto 8000 en uso

Problema: "Address already in use" al ejecutar uvicorn.
Solución: Usa otro puerto: uvicorn app.main:app --reload --port 8001. Ajusta las URLs de prueba.

ImportError al correr uvicorn

Problema: "No module named 'app'" o "No module named 'fastapi'".
Solución: Ejecuta uvicorn desde la carpeta que contiene app/ (la raíz del proyecto). Activa el venv y comprueba que pip list muestra fastapi y uvicorn.


Qué viene después: FastAPI Advanced Features Guide

Has completado los fundamentos. La guía avanzada agrega:

TemaQué aprenderásAplicación al To-Do API
Dependency InjectionServicios, conexiones a BD, auth como dependencias inyectablesSeparar lógica de negocio en servicios reutilizables
APIRouterEstructura modular, rutas por dominioMover endpoints de tareas a routers/tasks.py
WebSocketsComunicación en tiempo realNotificaciones cuando se crea/actualiza una tarea
Background TasksProcesamiento asíncrono sin bloquear la respuestaEnvío de emails, generación de reportes
File uploads y streamingArchivos grandes, descargasAdjuntar archivos a tareas
Middleware avanzadoLogging, metrics, rate limitingProteger la API de abuso

El To-Do List API que construiste es la base conceptual. En la guía avanzada lo evolucionarás con bases de datos reales (PostgreSQL + SQLAlchemy), autenticación, WebSockets para notificaciones en vivo y arquitectura modular.

Otros guías en el path

  • PostgreSQL & SQLAlchemy — Persistencia real: reemplazar tasks_db por tablas y sesiones. Las tareas sobrevivirán reinicios.
  • Authentication & Authorization — Proteger endpoints con JWT, roles y permisos. Solo usuarios autenticados podrían crear o editar tareas.

Portfolio tips

Plantilla README.md

Copia esto como base para tu README. En la sección Setup, usa un bloque de código bash:

# To-Do List API

API REST con FastAPI para gestionar tareas. Proyecto del Módulo 6 — FastAPI Fundamentals.

## Tecnologías

- FastAPI
- Pydantic
- Uvicorn

## Setup

    git clone <tu-repo>
    cd todo-api
    python -m venv venv
    source venv/bin/activate   # Windows: venv\Scripts\activate
    pip install -r requirements.txt
    uvicorn app.main:app --reload

## Endpoints

- GET / — Info del servicio
- GET /tasks — Lista con filtros, paginación, ordenamiento
- GET /tasks/{id} — Obtener tarea
- POST /tasks — Crear tarea
- PUT /tasks/{id} — Actualizar completa
- PATCH /tasks/{id} — Actualizar parcial
- DELETE /tasks/{id} — Eliminar tarea

## Documentación

- Swagger UI: http://localhost:8000/docs
- ReDoc: http://localhost:8000/redoc

Qué destacar en entrevistas

  • Arquitectura REST: Uso correcto de métodos HTTP (GET, POST, PUT, PATCH, DELETE) y códigos de estado (200, 201, 404, 422).
  • Validación con Pydantic: Separación de modelos Create/Update/Response, Literal para enums, Field constraints.
  • Error handling: Exception handlers con formato JSON consistente para HTTPException y RequestValidationError.
  • CORS: Capacidad de consumir la API desde un frontend en otro origen.

Cómo extender para impresionar

  • Añadir GET /tasks/stats que devuelva conteo por status — demuestra agregaciones.
  • Implementar persistencia en JSON (guardar/cargar tasks_db en archivo) — demuestra I/O.
  • Crear un frontend mínimo (HTML + fetch) que consuma la API — demuestra integración full-stack.

Repositorio GitHub

Si subes el proyecto a GitHub, incluye un archivo .gitignore con al menos venv/, __pycache__/ y *.pyc. Etiqueta el repo con topics como fastapi, python, rest-api para que sea más fácil de encontrar. Un buen README con instrucciones claras y ejemplos de uso aumenta mucho el valor del proyecto en tu portfolio.


Retrospectiva 4Ls

Reflexiona y, si puedes, escribe tus respuestas. Aproximadamente 2-3 frases por apartado.

Loved (me encantó)

Pregunta: ¿Qué disfrutaste más al construir este proyecto?

Ejemplos para inspirarte:

  • Integrar todo lo aprendido en un proyecto completo
  • Ver cómo Pydantic, path operations, query params y error handling encajan
  • Tener una API funcional lista para portfolio

Learned (aprendí)

Pregunta: ¿Qué conceptos o técnicas consolidaste?

Ejemplos:

  • Cómo construir un CRUD completo con FastAPI
  • Separación de modelos Create, Update, Response
  • Formato consistente de errores con exception handlers
  • Filtros, ordenamiento y paginación en un solo endpoint

Lacked (faltó)

Pregunta: ¿Qué echaste en falta o qué se quedó a medias?

Ejemplos:

  • Base de datos persistente (por ahora en memoria)
  • Autenticación y autorización
  • Tests automatizados

Longed for (me hubiera gustado)

Pregunta: ¿Qué te habría gustado hacer si tuvieras más tiempo?

Ejemplos:

  • Más tiempo para extender (categorías, due dates, etc.)
  • Integrar con un frontend real

Ideas para extender (opcional)

  • Agregar campo due_date opcional con validación de fecha futura
  • Implementar categorías o etiquetas para tareas
  • Agregar endpoint GET /tasks/stats que retorne conteo por status
  • Persistencia con JSON (guardar/cargar tasks_db en archivo)
  • README.md con instrucciones de setup y ejemplos con curl

Consejos finales antes de entregar

Antes de dar por cerrada la entrega, revisa estos puntos:

  1. Reinicia el servidor — Cierra uvicorn, vuelve a ejecutarlo y comprueba que todo arranca sin errores. A veces un cambio reciente introduce un bug que solo se revela al reiniciar.
  2. Prueba el flujo completo — Sigue la tabla del "Flujo de verificación completo" de principio a fin en una sola sesión. Si falla algún paso, corrige antes de entregar.
  3. Revisa la rúbrica — Pasa por cada ítem de la rúbrica y comprueba que cumples el criterio. Si dudas en alguno, vuelve a la cápsula correspondiente.
  4. Limpia el código — Elimina comentarios de depuración, prints y código comentado que no aporte. Un main.py limpio refleja profesionalidad.
  5. Prepara el README — Si vas a compartir el proyecto (GitHub, portfolio), usa la plantilla de la sección "Portfolio tips" para que cualquiera pueda ejecutarlo sin preguntar.

Consejos finales antes de entregar

Antes de dar por cerrada la entrega, haz esta comprobación rápida:

  1. Reinicia el servidor desde cero — Cierra uvicorn, activa el venv en una terminal nueva y ejecuta de nuevo. Así verificas que no hay dependencias de sesiones previas.
  2. Prueba el flujo completo en una sesión limpia — Reinicia el servidor (las tareas volverán a las 3 iniciales) y ejecuta los 11 pasos del flujo de verificación. Todo debe funcionar de principio a fin.
  3. Revisa /docs — Abre Swagger UI y confirma que cada endpoint muestra los parámetros correctos y que "Try it out" responde como esperas.
  4. Cierra la retrospectiva 4Ls — Escribir aunque sea unas líneas en cada L te ayuda a fijar lo aprendido y a identificar qué quieres profundizar después.

Conexión con el path de aprendizaje

Este proyecto completa la Guía #6: FastAPI Fundamentals del path Backend Python Developer. Siguiente guía en el path:

  • Guía #7: FastAPI Advanced Features — Dependency injection, APIRouter, WebSockets, background tasks, middleware avanzado

El To-Do List API que construiste sirve como base conceptual. En la guía avanzada lo extenderás con persistencia real, autenticación y arquitectura modular.


Resumen

Has construido una To-Do List API completa que integra:

  • ✅ Setup y estructura de proyecto
  • ✅ Path operations (GET, POST, PUT, PATCH, DELETE)
  • ✅ Request/Response con path y query params
  • ✅ Pydantic para validación y modelos
  • ✅ Error handling profesional con formato consistente
  • ✅ CORS para consumo desde frontend

Este proyecto demuestra dominio de los fundamentos de FastAPI y está listo para tu portfolio. La guía FastAPI Fundamentals queda completada.


Recursos adicionales

  1. FastAPI Documentation — Documentación oficial
  2. Pydantic Documentation — Validación y modelos
  3. FastAPI Advanced User Guide — Dependency injection, APIRouter, middleware
  4. REST API Best Practices — Convenciones REST
  5. FastAPI — Handling Errors — Exception handlers y códigos de error
  6. MDN — CORS — Entender la política same-origin y los headers CORS

Módulo 6, Cápsula 06 — FastAPI Fundamentals Guide