Module 1: Setup and First API

Proyecto: Hello World API

Descripción del proyecto

En este proyecto integras todo lo que aprendiste en el Módulo 1: crearás una API completa con estructura profesional, múltiples endpoints organizados por categorías, documentación automática personalizada, y respuestas JSON consistentes.

No es un "hola mundo" trivial. Es un API con identidad propia, estructura escalable, y documentación que podrías mostrar a otro desarrollador. Es el esqueleto real sobre el que construirás los módulos 2-6 de esta guía. Cada módulo posterior agregará una capa: CRUD (Módulo 2), parámetros avanzados (Módulo 3), validación Pydantic (Módulo 4), error handling y CORS (Módulo 5), hasta llegar al proyecto final To-Do List API (Módulo 6).

El objetivo es que al terminar, tengas un proyecto en tu máquina que funciona, tiene buena estructura, y sirve como base real — no como ejemplo descartable.


Objetivo del proyecto

Construir una Hello World API profesional que demuestre dominio de setup, endpoints GET, path parameters, y documentación automática en FastAPI.

Al completar este proyecto:

  • ✅ Tienes un proyecto FastAPI con estructura de carpetas profesional
  • ✅ Tu API tiene al menos 6 endpoints GET organizados con tags
  • ✅ La documentación en /docs tiene título, descripción y versión personalizados
  • ✅ Path parameters funcionan con validación de tipos automática
  • ✅ Respuestas JSON siguen un formato consistente
  • ✅ El servidor corre con hot reload y puedes iterar rápido

¿Por qué este proyecto?

Un Hello World API podría ser un solo endpoint. Pero este proyecto tiene 6 endpoints intencionalmente:

  • Endpoints informativos (/, /health, /info) — practican rutas estáticas y respuestas fijas
  • Endpoints dinámicos (/greet/{name}, /repeat/{message}/{times}) — practican path parameters con diferentes tipos
  • Endpoint con lógica (/age/{years}) — practica condicionales dentro de un endpoint

Esta variedad asegura que dominas los patrones básicos, no solo el caso trivial.

Además, este proyecto te obliga a pensar en organización desde el inicio — tags, documentación, formato de respuestas consistente.

Estos hábitos en el Módulo 6 harán la diferencia entre un proyecto amateur y uno profesional.


Especificaciones técnicas

Stack

  • Lenguaje: Python 3.9+
  • Framework: FastAPI
  • Servidor: uvicorn con hot reload
  • Dependencias: fastapi, uvicorn[standard]

Estructura del proyecto

fastapi-fundamentals/
├── venv/
├── app/
│   ├── __init__.py
│   └── main.py
├── requirements.txt
└── .gitignore

Esta estructura es idéntica a la que configuraste en la Cápsula 02. No necesitas crear archivos adicionales — todo el código va en app/main.py.

En módulos posteriores esta estructura crecerá con archivos como models.py y carpetas como routers/, pero por ahora un solo archivo es suficiente para mantener el foco en los conceptos fundamentales.

Setup (si empiezas desde cero)

mkdir fastapi-fundamentals
cd fastapi-fundamentals
python -m venv venv
source venv/bin/activate  # Mac/Linux
pip install fastapi "uvicorn[standard]"
pip freeze > requirements.txt
mkdir -p app
touch app/__init__.py app/main.py

Funcionalidades obligatorias

Tu Hello World API debe tener estos endpoints:

1. Root — Información del servicio

GET /
Response:
{
  "service": "Hello World API",
  "version": "1.0.0",
  "status": "running",
  "documentation": "/docs"
}

2. Health Check

GET /health
Response:
{
  "status": "healthy"
}

3. API Info — Metadatos completos

GET /info
Response:
{
  "name": "Hello World API",
  "description": "Mi primera API profesional con FastAPI",
  "version": "1.0.0",
  "author": "Tu Nombre",
  "python_framework": "FastAPI",
  "documentation_urls": {
    "swagger": "/docs",
    "redoc": "/redoc",
    "openapi": "/openapi.json"
  }
}

4. Greet — Saludo personalizado

GET /greet/{name}
Response:
{
  "message": "Hello, Maria!",
  "name": "Maria"
}

5. Repeat — Repetir un mensaje N veces

GET /repeat/{message}/{times}
Response:
{
  "original": "hola",
  "times": 3,
  "result": "hola hola hola"
}

6. Age Category — Clasificar por edad

GET /age/{years}
Response:
{
  "age": 25,
  "category": "adult",
  "can_vote": true,
  "can_drive": true
}

Formato de respuesta consistente

Todas las respuestas deben seguir estas convenciones:

  • Siempre retornar diccionarios (JSON objects), no strings ni listas sueltas
  • Usar snake_case para las keys (can_vote, no canVote)
  • Incluir el input del usuario en la respuesta cuando sea relevante (facilita debugging)
  • Los endpoints de error deben incluir una key "error" con un mensaje descriptivo
# ✅ Buena respuesta — consistente, informativa
{
    "age": 25,
    "category": "adult",
    "can_vote": true
}

# ❌ Mala respuesta — solo el resultado sin contexto
"adult"

Documentación personalizada

Tu aplicación FastAPI debe incluir:

  • Título: "Hello World API"
  • Descripción: Un párrafo describiendo la API
  • Versión: "1.0.0"
  • Tags: Al menos 3 tags para organizar endpoints (ej: "General", "System", "Features")
  • Cada endpoint debe tener summary o docstring descriptivo

Código completo comentado

app/main.py

from fastapi import FastAPI

app = FastAPI(
    title="Hello World API",
    description="Mi primera API profesional con FastAPI. Incluye endpoints de información, saludo personalizado y clasificación por edad.",
    version="1.0.0",
)


# --- Endpoints Generales ---

@app.get("/", tags=["General"], summary="Service Info")
def root():
    """Punto de entrada principal. Retorna información básica del servicio."""
    return {
        "service": "Hello World API",
        "version": "1.0.0",
        "status": "running",
        "documentation": "/docs"
    }


@app.get("/health", tags=["System"], summary="Health Check")
def health_check():
    """Verifica que el servicio está activo y respondiendo correctamente."""
    return {"status": "healthy"}


@app.get("/info", tags=["System"], summary="API Metadata")
def api_info():
    """
    Retorna metadatos completos de la API.

    Incluye nombre, versión, autor y URLs de documentación.
    """
    return {
        "name": "Hello World API",
        "description": "Mi primera API profesional con FastAPI",
        "version": "1.0.0",
        "author": "Tu Nombre",
        "python_framework": "FastAPI",
        "documentation_urls": {
            "swagger": "/docs",
            "redoc": "/redoc",
            "openapi": "/openapi.json"
        }
    }


# --- Endpoints de Features ---

@app.get("/greet/{name}", tags=["Features"], summary="Greet User")
def greet(name: str):
    """
    Saluda al usuario por su nombre.

    - **name**: Nombre de la persona (string)
    """
    return {
        "message": f"Hello, {name}!",
        "name": name
    }


@app.get("/repeat/{message}/{times}", tags=["Features"], summary="Repeat Message")
def repeat_message(message: str, times: int):
    """
    Repite un mensaje N veces.

    - **message**: Texto a repetir
    - **times**: Cantidad de repeticiones (entero positivo)
    """
    repeated = " ".join([message] * times)
    return {
        "original": message,
        "times": times,
        "result": repeated
    }


@app.get("/age/{years}", tags=["Features"], summary="Age Category")
def age_category(years: int):
    """
    Clasifica una edad en categoría y determina permisos básicos.

    **Categorías:**
    - **child**: 0-12 años
    - **teenager**: 13-17 años
    - **adult**: 18-64 años
    - **senior**: 65+ años
    """
    if years < 0:
        return {
            "error": "Age cannot be negative",
            "input": years
        }

    if years <= 12:
        category = "child"
    elif years <= 17:
        category = "teenager"
    elif years <= 64:
        category = "adult"
    else:
        category = "senior"

    return {
        "age": years,
        "category": category,
        "can_vote": years >= 18,
        "can_drive": years >= 16
    }

Ejecutar

uvicorn app.main:app --reload

Probar todos los endpoints

# General
curl -s http://127.0.0.1:8000/ | python -m json.tool
curl -s http://127.0.0.1:8000/health | python -m json.tool
curl -s http://127.0.0.1:8000/info | python -m json.tool

# Features
curl -s http://127.0.0.1:8000/greet/FastAPI | python -m json.tool
curl -s http://127.0.0.1:8000/repeat/hola/3 | python -m json.tool
curl -s http://127.0.0.1:8000/age/25 | python -m json.tool
curl -s http://127.0.0.1:8000/age/10 | python -m json.tool
curl -s http://127.0.0.1:8000/age/70 | python -m json.tool

# Documentación
# Abre en navegador: http://127.0.0.1:8000/docs
# Abre en navegador: http://127.0.0.1:8000/redoc

Outputs esperados:

# GET /
{
    "service": "Hello World API",
    "version": "1.0.0",
    "status": "running",
    "documentation": "/docs"
}

# GET /health
{
    "status": "healthy"
}

# GET /greet/FastAPI
{
    "message": "Hello, FastAPI!",
    "name": "FastAPI"
}

# GET /repeat/hola/3
{
    "original": "hola",
    "times": 3,
    "result": "hola hola hola"
}

# GET /age/25
{
    "age": 25,
    "category": "adult",
    "can_vote": true,
    "can_drive": true
}

# GET /age/10
{
    "age": 10,
    "category": "child",
    "can_vote": false,
    "can_drive": false
}

Criterios de éxito

Tu proyecto está completo cuando:

  • ✅ El servidor inicia sin errores con uvicorn app.main:app --reload
  • ✅ Todos los 6 endpoints retornan respuestas JSON correctas
  • /docs muestra la documentación con título "Hello World API"
  • ✅ Los endpoints están organizados en al menos 3 tags
  • ✅ Path parameters funcionan (/greet/nombre, /age/25)
  • ✅ Validación de tipos funciona (/age/abc retorna error 422)
  • ✅ Hot reload funciona (editas código, guardas, y el cambio se refleja)
  • ✅ La estructura del proyecto usa app/main.py (no main.py en raíz)

Checklist de completitud

Estructura:
- [ ] Carpeta app/ con __init__.py y main.py
- [ ] requirements.txt generado
- [ ] .gitignore configurado
- [ ] Virtual environment funcional

Endpoints (6):
- [ ] GET / — Info del servicio
- [ ] GET /health — Health check
- [ ] GET /info — Metadatos completos
- [ ] GET /greet/{name} — Saludo personalizado
- [ ] GET /repeat/{message}/{times} — Repetir mensaje
- [ ] GET /age/{years} — Categoría por edad

Documentación:
- [ ] Título personalizado en /docs
- [ ] Descripción de la API
- [ ] Versión configurada
- [ ] Tags organizando endpoints
- [ ] Summary o docstring en cada endpoint

Funcionamiento:
- [ ] Servidor inicia sin errores
- [ ] Hot reload funciona
- [ ] Validación de tipos funciona (int en path params)
- [ ] Respuestas JSON consistentes

Errores comunes

Error 1: "detail": "Not Found" en un endpoint

Causa: La ruta en el navegador/curl no coincide exactamente con la del decorador.

Solución:

# Si definiste:
@app.get("/greet/{name}")

# Accede a:
# ✅ /greet/Maria
# ❌ /Greet/Maria   (case sensitive)
# ❌ /greet/         (falta el parámetro)
# ❌ /greet          (falta / y parámetro)

Error 2: times se interpreta como string

Causa: Olvidaste el type hint int en el parámetro.

Solución:

# ❌ Sin type hint — times es string
@app.get("/repeat/{message}/{times}")
def repeat_message(message: str, times):  # times será str
    repeated = " ".join([message] * times)  # Error: can't multiply by str

# ✅ Con type hint — times es int
@app.get("/repeat/{message}/{times}")
def repeat_message(message: str, times: int):  # times será int
    repeated = " ".join([message] * times)  # Funciona

Error 3: El diccionario JSON retorna en una sola línea ilegible

Causa: Esto es normal. JSON por defecto es compacto. Para formato bonito:

Solución:

# Desde terminal, usa python para formatear:
curl -s http://127.0.0.1:8000/info | python -m json.tool

# O instala jq (herramienta de línea de comandos para JSON):
curl -s http://127.0.0.1:8000/info | jq

Error 4: Los tags no aparecen en /docs

Causa: Olvidaste el parámetro tags en el decorador.

Solución:

# ❌ Sin tags
@app.get("/health")
def health_check():
    return {"status": "healthy"}

# ✅ Con tags
@app.get("/health", tags=["System"])
def health_check():
    return {"status": "healthy"}

Error 5: Hot reload no detecta cambios

Causa: Editaste un archivo fuera de la carpeta que uvicorn monitorea, o hay un error de sintaxis que impide la recarga.

Solución:

# Verificar que no hay errores de sintaxis en la terminal de uvicorn
# Si ves un traceback, corrígelo primero

# Si no detecta cambios, reinicia manualmente:
# Ctrl+C para detener
uvicorn app.main:app --reload

Verificación paso a paso

Usa esta guía para verificar que tu proyecto funciona correctamente:

Paso 1: Verificar estructura

# Desde la raíz del proyecto
ls -la app/
# Debe mostrar:
# __init__.py
# main.py

ls requirements.txt
# Debe existir

ls .gitignore
# Debe existir

Paso 2: Verificar servidor

# Iniciar servidor
uvicorn app.main:app --reload

# En otra terminal, probar root:
curl -s http://127.0.0.1:8000/ | python -m json.tool
# Debe retornar JSON con "service", "version", "status", "documentation"

Paso 3: Verificar documentación

Abre http://127.0.0.1:8000/docs en tu navegador:

  • ¿El título dice "Hello World API"? ✅
  • ¿Ves la descripción personalizada? ✅
  • ¿Los endpoints están agrupados en tags? ✅
  • ¿Puedes hacer "Try it out" en cualquier endpoint? ✅

Paso 4: Verificar path parameters

# String parameter
curl -s http://127.0.0.1:8000/greet/TestUser | python -m json.tool
# Debe incluir "TestUser" en la respuesta

# Int parameter
curl -s http://127.0.0.1:8000/age/25 | python -m json.tool
# Debe retornar category "adult"

# Validación de tipos
curl -s http://127.0.0.1:8000/age/abc | python -m json.tool
# Debe retornar error 422

Paso 5: Verificar hot reload

  1. Con el servidor corriendo, edita cualquier respuesta en app/main.py
  2. Guarda el archivo
  3. Verifica que la terminal de uvicorn muestra "Reloading..."
  4. Refresca el navegador — el cambio debe reflejarse

Ideas para extender (opcional)

Si terminas rápido y quieres practicar más, agrega estos endpoints. No son obligatorios pero refuerzan lo aprendido:

@app.get("/reverse/{text}", tags=["Features"], summary="Reverse Text")
def reverse_text(text: str):
    """Invierte un string."""
    return {
        "original": text,
        "reversed": text[::-1]
    }


@app.get("/count/{text}", tags=["Features"], summary="Count Characters")
def count_chars(text: str):
    """Cuenta caracteres, palabras y vocales en un texto."""
    vowels = sum(1 for c in text.lower() if c in "aeiou")
    return {
        "text": text,
        "characters": len(text),
        "words": len(text.split("-")),
        "vowels": vowels
    }


@app.get("/fibonacci/{n}", tags=["Features"], summary="Fibonacci Number")
def fibonacci(n: int):
    """Calcula el n-ésimo número de Fibonacci."""
    if n < 0:
        return {"error": "n must be non-negative"}

    a, b = 0, 1
    for _ in range(n):
        a, b = b, a + b

    return {
        "n": n,
        "fibonacci": a
    }

Troubleshooting del proyecto

Si algo no funciona, sigue este diagnóstico en orden:

1. ¿El venv está activo?
   → ¿Ves (venv) en el prompt?
   → source venv/bin/activate

2. ¿FastAPI está instalado?
   → pip show fastapi
   → Si no, pip install fastapi "uvicorn[standard]"

3. ¿El servidor inicia?
   → uvicorn app.main:app --reload
   → Si hay error, lee el traceback completo

4. ¿El endpoint existe?
   → Abre /docs y verifica que la ruta está listada
   → Si no aparece, revisa el decorador

5. ¿La respuesta es correcta?
   → Usa "Try it out" en /docs para probar
   → Compara la respuesta con la especificación

Problemas frecuentes y soluciones rápidas

SíntomaCausa probableSolución
ModuleNotFoundError: No module named 'fastapi'venv no activosource venv/bin/activate
ModuleNotFoundError: No module named 'app'Directorio incorrectocd a la raíz del proyecto
ERROR: Address already in usePuerto 8000 ocupado--port 8001 o matar proceso
404 Not Found en un endpointRuta mal escritaComparar ruta con decorador
422 Unprocessable EntityTipo de parámetro incorrectoVerificar type hints
Cambios no se reflejanHot reload no detectóCtrl+C y reiniciar uvicorn
/docs vacíoError de sintaxis en códigoRevisar terminal de uvicorn
SyntaxError al iniciarError en main.pyRevisar traceback completo

Rúbrica de evaluación (100 puntos)

Estructura y setup (20 puntos)

  • (5 pts) Virtual environment creado y funcional
  • (5 pts) Estructura app/ con __init__.py y main.py
  • (5 pts) requirements.txt generado con dependencias
  • (5 pts) .gitignore configurado correctamente

Endpoints (40 puntos)

  • (8 pts) GET / retorna información del servicio
  • (5 pts) GET /health retorna status healthy
  • (7 pts) GET /info retorna metadatos completos
  • (7 pts) GET /greet/{name} funciona con path parameter string
  • (7 pts) GET /repeat/{message}/{times} funciona con path parameter int
  • (6 pts) GET /age/{years} retorna categoría correcta

Documentación (20 puntos)

  • (5 pts) Título personalizado visible en /docs
  • (5 pts) Descripción de la API configurada
  • (5 pts) Endpoints organizados con tags (mínimo 3)
  • (5 pts) Summary o docstring en cada endpoint

Calidad de código (20 puntos)

  • (5 pts) Código limpio y legible
  • (5 pts) Type hints en todos los path parameters
  • (5 pts) Respuestas JSON consistentes (diccionarios)
  • (5 pts) Hot reload funcionando correctamente

Extra credit (hasta +10 puntos)

  • (+5 pts) Endpoint adicional creativo con lógica interesante
  • (+3 pts) Docstrings con formato Markdown renderizado en /docs
  • (+2 pts) Verificación de edge cases (ej: edad negativa)

Conexión con el siguiente módulo

Tu Hello World API es el punto de partida del Módulo 2 (Path Operations). En el siguiente módulo:

  • Agregarás POST, PUT, PATCH y DELETE — hasta ahora solo tienes GET
  • Implementarás datos en memoria — una lista de Python como mock database
  • Harás CRUD completo — crear, leer, actualizar y eliminar recursos

El código de app/main.py crecerá. La estructura app/ se mantendrá igual — la base que construiste aquí es duradera.

Lo que ya tienes funcionando:

  • Setup con venv + uvicorn + hot reload → lo conservas
  • Estructura app/main.py → la amplías
  • Documentación automática → se actualiza sola al agregar endpoints
  • Path parameters → los seguirás usando

Lo que agregarás en Módulo 2:

  • Operaciones POST, PUT, PATCH, DELETE
  • Lista en memoria como almacenamiento temporal
  • Endpoints que modifican estado (no solo lectura)
  • Response status codes apropiados (201 Created, 204 No Content)

Reflexión: Lo que ya dominas

Detente un momento y nota lo que ya sabes hacer después de este módulo:

  1. Crear un proyecto Python profesional con aislamiento de dependencias
  2. Definir endpoints HTTP que manejan requests y retornan JSON
  3. Usar path parameters con validación automática de tipos
  4. Generar documentación interactiva sin esfuerzo adicional
  5. Iterar rápido con hot reload — tu ciclo de feedback es de segundos

Estos 5 skills son la base de todo lo que viene. El Módulo 2 agrega verbos HTTP (POST, PUT, DELETE). El Módulo 3 agrega query parameters y request body. El Módulo 4 agrega validación con Pydantic. Cada módulo es una capa nueva sobre esta base sólida.

No subestimes lo que ya construiste. Un servidor con documentación automática, validación de tipos y hot reload es más de lo que muchos tutoriales cubren en varias horas.


Resumen

En este proyecto integraste los conceptos fundamentales del Módulo 1:

  • Setup profesional: Virtual environment, estructura app/, requirements.txt
  • Endpoints GET: 6 endpoints con rutas estáticas y dinámicas (path parameters)
  • Path parameters con tipos: Validación automática de int y str
  • Documentación personalizada: Título, descripción, versión, tags y docstrings
  • Hot reload: Flujo de desarrollo ágil con uvicorn --reload
  • Respuestas consistentes: Diccionarios JSON con formato predecible

Tu Hello World API no es un ejercicio descartable — es el esqueleto real sobre el que construirás el resto de la guía. Guarda este proyecto: lo abrirás al inicio del Módulo 2 y seguirás construyendo sobre él.

Módulo 1 completado. Siguiente parada: Path Operations — donde tu API aprende a crear, actualizar y eliminar recursos.


Lo que llevas al Módulo 2

Antes de avanzar, asegúrate de tener claro esto — es lo que asumirás como conocido a partir de ahora:

ConceptoNivel esperado
Virtual environmentSabes crear, activar y desactivar
pip installSabes instalar paquetes y generar requirements.txt
Estructura app/Entiendes por qué usas un paquete Python
@app.get("/ruta")Sabes que conecta ruta + verbo + función
Path parametersSabes usar {param} en rutas con type hints
uvicorn --reloadSabes levantar servidor con hot reload
/docsSabes probar endpoints desde el navegador
Respuestas JSONSabes retornar diccionarios que se serializan automáticamente

Si alguno de estos puntos no te queda claro, revisa la cápsula correspondiente antes de continuar.


Recursos para el proyecto

  1. FastAPI Tutorial - First Steps - Referencia oficial para endpoints básicos
  2. FastAPI - Path Parameters - Documentación de path parameters
  3. FastAPI - Metadata and Docs - Personalización de documentación
  4. Uvicorn - Settings - Opciones de configuración del servidor
  5. HTTP Status Codes - MDN - Referencia de status codes
  6. JSON.org - Especificación del formato JSON