Uso de parámetros en la ruta (Path y Query)

Cuando creamos endpoints en FastAPI, podemos recibir datos de dos formas muy comunes:

  • Parámetros en la ruta (Path Parameters): son parte de la URL.
  • Parámetros de consulta (Query Parameters): aparecen después de ? en la URL.

Objetivos de la sección

  • Comprender la diferencia entre parámetros path y query.
  • Implementar endpoints que reciban datos desde la URL.
  • Validar y usar esos datos dentro de la función.
  • Probar los resultados en el navegador y en /docs.

Paso 1: Parámetros en la ruta (Path Parameters)

Un path parameter es un valor que se pasa directamente en la URL como parte de la ruta. Se define usando llaves { } en el decorador.

Ejemplo:

from fastapi import FastAPI

app = FastAPI()

@app.get("/saludo/{nombre}")
def saludar(nombre: str):
    return {"mensaje": f"Hola {nombre}, bienvenido a FastAPI!"}

Si abrimos en el navegador:

http://127.0.0.1:8000/saludo/Diego

{"mensaje": "Hola Diego, bienvenido a FastAPI!"}

http://127.0.0.1:8000/saludo/Maria

{"mensaje": "Hola Maria, bienvenido a FastAPI!"}

Explicación:

  • @app.get("/saludo/{nombre}"): {nombre} es un parámetro de la ruta.
  • def saludar(nombre: str): FastAPI lo convierte en variable dentro de la función. El tipo str asegura que se reciba texto.

Paso 2: Parámetros de consulta (Query Parameters)

Los query parameters se pasan en la URL después de ? y separados con &. Se definen como argumentos de la función con valores por defecto.

Ejemplo:

@app.get("/productos")

def filtrar_productos(categoria: str | None = None, limite: int = 5):
    return {
        "categoria": categoria,
        "limite": limite,
        "mensaje": "Aquí iría la lógica para devolver productos filtrados"
    }

Probar en el navegador:

http://127.0.0.1:8000/productos

{"categoria": null, "limite": 5, "mensaje": "Aquí iría la lógica para devolver productos filtrados"}

http://127.0.0.1:8000/productos?categoria=electronica

{"categoria": "electronica", "limite": 5, "mensaje": "Aquí iría la lógica para devolver productos filtrados"}

http://127.0.0.1:8000/productos?categoria=ropa&limite=2

{"categoria": "ropa", "limite": 2, "mensaje": "Aquí iría la lógica para devolver productos filtrados"}

Explicación:

  • categoria: str | None = None: parámetro opcional.
  • limite: int = 5: parámetro con valor por defecto.
  • Si no se envían, FastAPI usa los valores por defecto.

Paso 3: Ejemplo combinado (Path + Query)

Podemos usar ambos tipos de parámetros juntos en el mismo endpoint.

Ejemplo:

@app.get("/usuarios/{usuario_id}")

def obtener_usuario(usuario_id: int, activo: bool = True):
    return {
        "usuario_id": usuario_id,
        "activo": activo
    }

Probar en el navegador:

http://127.0.0.1:8000/usuarios/10

{"usuario_id": 10, "activo": true}

http://127.0.0.1:8000/usuarios/10?activo=false

{"usuario_id": 10, "activo": false}

Explicación:

  • usuario_id viene de la ruta (Path).
  • activo viene de la query (Query).

Conclusión

  • Path Parameters: parte de la URL (/saludo/Diego).
  • Query Parameters: después de ? en la URL (/productos?categoria=ropa).
  • Se pueden combinar para crear endpoints más flexibles y potentes.

Problema propuesto

Queremos construir un traductor básico que reciba una palabra en castellano y devuelva su traducción a otro idioma.

Requisitos

Endpoint
GET /traducir/{palabra}

Base de datos simulada (diccionario)

diccionario = {
    "hola": {"en": "hello", "fr": "bonjour", "it": "ciao"},
    "perro": {"en": "dog", "fr": "chien", "it": "cane"},
    "gato": {"en": "cat", "fr": "chat", "it": "gatto"},
    "casa": {"en": "house", "fr": "maison", "it": "casa"},
    "gracias": {"en": "thank you", "fr": "merci", "it": "grazie"}
}

Parámetro Path

{palabra}: palabra en castellano que se quiere traducir.

Parámetro Query (opcional)

idioma (str): idioma destino (en, fr, it). Por defecto, si no se envía, debe devolver la traducción en inglés (en).

Respuestas esperadas

  • Si la palabra existe: devolver JSON con la traducción.
  • Si no existe en el diccionario: devolver 404 con {"detail": "Palabra no encontrada"}.
  • Si el idioma no existe para esa palabra: devolver 400 con {"detail": "Idioma no soportado"}.

Casos de prueba

Traducción por defecto (inglés)

/traducir/hola

{"palabra":"hola","traduccion":"hello","idioma":"en"}

Traducción a francés (query param)

/traducir/gato?idioma=fr

{"palabra":"gato","traduccion":"chat","idioma":"fr"}

Traducción a italiano

/traducir/perro?idioma=it

{"palabra":"perro","traduccion":"cane","idioma":"it"}

Palabra no encontrada

/traducir/arbol

{"detail":"Palabra no encontrada"}

Idioma no soportado

/traducir/hola?idioma=de

{"detail":"Idioma no soportado"}

Pistas (sin código)

@app.get("/traducir/{palabra}")

def traducir(palabra: str, idioma: str = "en"):
    ...
  • Convertir la palabra a minúsculas antes de buscar (palabra.lower()).
  • Usar .get() en el diccionario para acceder a las traducciones.
  • Validar que idioma exista dentro de los valores posibles (en, fr, it).