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.
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