Rutas endpoints REST GET

Intermedio
Flask
Flask
Actualizado: 20/06/2025

¡Desbloquea el curso completo!

IA
Ejercicios
Certificado
Entrar

Rutas básicas con @app.route()

Flask utiliza el decorador @app.route() para definir las rutas de nuestra aplicación web. Este decorador vincula una URL específica con una función Python, estableciendo así los endpoints que los clientes pueden solicitar mediante peticiones HTTP.

La sintaxis básica del decorador es sencilla: se coloca directamente encima de la función que queremos asociar con una ruta específica. Cuando un usuario accede a esa URL, Flask ejecuta automáticamente la función correspondiente.

from flask import Flask

app = Flask(__name__)

@app.route('/')
def inicio():
    return "¡Bienvenido a nuestra API!"

if __name__ == '__main__':
    app.run(debug=True)

En este ejemplo, el decorador @app.route('/') asocia la URL raíz con la función inicio(). Cuando alguien visite http://localhost:5000/, Flask ejecutará esta función y devolverá el mensaje de bienvenida.

Definición de rutas con parámetros

Las rutas pueden incluir parámetros dinámicos que se capturan desde la URL y se pasan como argumentos a la función. Estos parámetros se definen entre corchetes angulares dentro de la ruta.

@app.route('/usuario/<nombre>')
def mostrar_usuario(nombre):
    return f"Perfil del usuario: {nombre}"

@app.route('/producto/<int:id>')
def obtener_producto(id):
    return f"Información del producto con ID: {id}"

Flask permite especificar el tipo de dato del parámetro utilizando convertidores como int, float, string o path. Esto garantiza que el parámetro tenga el formato correcto antes de ejecutar la función.

# Datos de ejemplo en memoria
productos = [
    {"id": 1, "nombre": "Laptop", "precio": 899.99},
    {"id": 2, "nombre": "Mouse", "precio": 25.50},
    {"id": 3, "nombre": "Teclado", "precio": 75.00}
]

@app.route('/productos')
def listar_productos():
    return str(productos)

@app.route('/productos/<int:producto_id>')
def obtener_producto_por_id(producto_id):
    producto = next((p for p in productos if p["id"] == producto_id), None)
    if producto:
        return str(producto)
    return "Producto no encontrado", 404

Especificación de métodos HTTP

Por defecto, las rutas de Flask solo responden a peticiones GET. Para una API REST, necesitamos especificar explícitamente qué métodos HTTP acepta cada ruta utilizando el parámetro methods.

@app.route('/api/productos', methods=['GET'])
def api_listar_productos():
    return str(productos)

@app.route('/api/productos/<int:producto_id>', methods=['GET'])
def api_obtener_producto(producto_id):
    producto = next((p for p in productos if p["id"] == producto_id), None)
    if producto:
        return str(producto)
    return "Producto no encontrado", 404

Aunque en este ejemplo especificamos methods=['GET'] de forma explícita, esto es opcional para peticiones GET ya que es el comportamiento por defecto. Sin embargo, es una buena práctica incluirlo para mayor claridad en APIs REST.

Organización de rutas con prefijos

Para mantener una estructura clara en nuestra API, podemos organizar las rutas utilizando prefijos comunes. Esto facilita la comprensión y el mantenimiento del código.

# Datos de ejemplo para diferentes recursos
usuarios = [
    {"id": 1, "nombre": "Ana", "email": "ana@email.com"},
    {"id": 2, "nombre": "Carlos", "email": "carlos@email.com"}
]

categorias = [
    {"id": 1, "nombre": "Electrónicos"},
    {"id": 2, "nombre": "Oficina"}
]

# Rutas para usuarios
@app.route('/api/usuarios', methods=['GET'])
def obtener_usuarios():
    return str(usuarios)

@app.route('/api/usuarios/<int:usuario_id>', methods=['GET'])
def obtener_usuario(usuario_id):
    usuario = next((u for u in usuarios if u["id"] == usuario_id), None)
    if usuario:
        return str(usuario)
    return "Usuario no encontrado", 404

# Rutas para categorías
@app.route('/api/categorias', methods=['GET'])
def obtener_categorias():
    return str(categorias)

@app.route('/api/categorias/<int:categoria_id>', methods=['GET'])
def obtener_categoria(categoria_id):
    categoria = next((c for c in categorias if c["id"] == categoria_id), None)
    if categoria:
        return str(categoria)
    return "Categoría no encontrada", 404

Esta estructura con el prefijo /api/ establece una convención clara para distinguir los endpoints de la API del resto de rutas que pueda tener la aplicación. Cada recurso (usuarios, categorías, productos) tiene sus propias rutas organizadas de forma coherente.

Las rutas que hemos definido siguen el patrón REST básico: una ruta para obtener todos los elementos de un recurso (/api/usuarios) y otra para obtener un elemento específico por su identificador (/api/usuarios/<id>). Este enfoque proporciona una base sólida para construir APIs más complejas.

¿Te está gustando esta lección?

Inicia sesión para no perder tu progreso y accede a miles de tutoriales, ejercicios prácticos y nuestro asistente de IA.

Progreso guardado
Asistente IA
Ejercicios
Iniciar sesión gratis

Más de 25.000 desarrolladores ya confían en CertiDevs

Respuestas JSON con jsonify()

En las APIs REST modernas, el formato JSON (JavaScript Object Notation) se ha convertido en el estándar para el intercambio de datos entre cliente y servidor. Flask proporciona la función jsonify() para convertir automáticamente estructuras de datos de Python en respuestas JSON válidas con las cabeceras HTTP correctas.

La función jsonify() no solo convierte los datos a formato JSON, sino que también establece el Content-Type de la respuesta como application/json, lo cual es esencial para que los clientes interpreten correctamente la información recibida.

from flask import Flask, jsonify

app = Flask(__name__)

# Datos de ejemplo en memoria
productos = [
    {"id": 1, "nombre": "Laptop", "precio": 899.99, "stock": 15},
    {"id": 2, "nombre": "Mouse", "precio": 25.50, "stock": 50},
    {"id": 3, "nombre": "Teclado", "precio": 75.00, "stock": 30}
]

@app.route('/api/productos', methods=['GET'])
def obtener_productos():
    return jsonify(productos)

Respuestas JSON para recursos individuales

Cuando trabajamos con recursos específicos, jsonify() maneja tanto diccionarios individuales como casos donde el recurso no existe. Es importante devolver respuestas JSON consistentes en ambos escenarios.

@app.route('/api/productos/<int:producto_id>', methods=['GET'])
def obtener_producto(producto_id):
    producto = next((p for p in productos if p["id"] == producto_id), None)
    
    if producto:
        return jsonify(producto)
    
    # Respuesta JSON para errores
    return jsonify({"error": "Producto no encontrado"}), 404

La función jsonify() acepta tanto diccionarios como listas, y automáticamente los serializa al formato JSON apropiado. Observa cómo podemos combinar la respuesta JSON con códigos de estado HTTP para proporcionar información completa sobre el resultado de la operación.

Estructuración de respuestas JSON complejas

Para APIs más robustas, es común estructurar las respuestas JSON con metadatos adicionales que proporcionen contexto sobre los datos devueltos. Esto mejora la experiencia del desarrollador que consume la API.

@app.route('/api/productos/buscar/<string:termino>', methods=['GET'])
def buscar_productos(termino):
    resultados = [
        p for p in productos 
        if termino.lower() in p["nombre"].lower()
    ]
    
    respuesta = {
        "termino_busqueda": termino,
        "total_resultados": len(resultados),
        "productos": resultados
    }
    
    return jsonify(respuesta)

Respuestas JSON con información de estado

Las APIs REST efectivas proporcionan información de estado clara en sus respuestas. Podemos usar jsonify() para crear respuestas estructuradas que incluyan tanto los datos como metadatos sobre la operación.

usuarios = [
    {"id": 1, "nombre": "Ana", "email": "ana@email.com", "activo": True},
    {"id": 2, "nombre": "Carlos", "email": "carlos@email.com", "activo": False}
]

@app.route('/api/usuarios', methods=['GET'])
def obtener_usuarios():
    usuarios_activos = [u for u in usuarios if u["activo"]]
    
    respuesta = {
        "status": "success",
        "data": {
            "usuarios": usuarios_activos,
            "total": len(usuarios_activos),
            "total_sistema": len(usuarios)
        }
    }
    
    return jsonify(respuesta)

@app.route('/api/estadisticas', methods=['GET'])
def obtener_estadisticas():
    stats = {
        "productos": {
            "total": len(productos),
            "en_stock": len([p for p in productos if p["stock"] > 0]),
            "valor_inventario": sum(p["precio"] * p["stock"] for p in productos)
        },
        "usuarios": {
            "total": len(usuarios),
            "activos": len([u for u in usuarios if u["activo"]])
        }
    }
    
    return jsonify(stats)

Manejo de tipos de datos especiales

Python incluye tipos de datos que no son directamente serializables a JSON, como datetime o Decimal. Flask's jsonify() maneja automáticamente los tipos básicos (strings, números, booleanos, listas, diccionarios), pero para tipos más complejos necesitamos convertirlos previamente.

from datetime import datetime

# Simulamos datos con fechas
pedidos = [
    {
        "id": 1,
        "producto_id": 1,
        "cantidad": 2,
        "fecha_creacion": "2024-01-15T10:30:00",
        "estado": "completado"
    },
    {
        "id": 2,
        "producto_id": 2,
        "cantidad": 1,
        "fecha_creacion": "2024-01-16T14:20:00",
        "estado": "pendiente"
    }
]

@app.route('/api/pedidos', methods=['GET'])
def obtener_pedidos():
    return jsonify(pedidos)

@app.route('/api/pedidos/<int:pedido_id>', methods=['GET'])
def obtener_pedido(pedido_id):
    pedido = next((p for p in pedidos if p["id"] == pedido_id), None)
    
    if not pedido:
        return jsonify({"error": "Pedido no encontrado"}), 404
    
    # Enriquecemos la respuesta con información del producto
    producto = next((p for p in productos if p["id"] == pedido["producto_id"]), None)
    
    respuesta = {
        "pedido": pedido,
        "producto_info": {
            "nombre": producto["nombre"] if producto else "Producto no disponible",
            "precio_unitario": producto["precio"] if producto else 0
        },
        "total": (producto["precio"] * pedido["cantidad"]) if producto else 0
    }
    
    return jsonify(respuesta)

La función jsonify() simplifica significativamente el desarrollo de APIs REST en Flask al automatizar la conversión de datos Python a JSON y establecer las cabeceras HTTP apropiadas. Esto nos permite concentrarnos en la lógica de negocio mientras Flask se encarga de los detalles de la serialización y el protocolo HTTP.

Aprendizajes de esta lección

  • Comprender cómo definir rutas básicas y con parámetros dinámicos en Flask usando @app.route().
  • Aprender a especificar métodos HTTP para endpoints REST, especialmente GET.
  • Organizar rutas con prefijos para estructurar una API REST coherente.
  • Utilizar jsonify() para devolver respuestas JSON correctamente formateadas y con cabeceras adecuadas.
  • Manejar respuestas JSON complejas, incluyendo códigos de estado HTTP y metadatos adicionales.

Completa Flask y certifícate

Únete a nuestra plataforma y accede a miles de tutoriales, ejercicios prácticos, proyectos reales y nuestro asistente de IA personalizado para acelerar tu aprendizaje.

Asistente IA

Resuelve dudas al instante

Ejercicios

Practica con proyectos reales

Certificados

Valida tus conocimientos

Más de 25.000 desarrolladores ya se han certificado con CertiDevs

⭐⭐⭐⭐⭐
4.9/5 valoración