Cada framwork web posee su propio mecanismo para gestionar las peticiones entrantes, y Flask no es la excepción. En este entorno, la interacción con las solicitudes HTTP se centraliza en el objeto request, el cual es proporcionado por la biblioteca subyacente Werkzeug. A continuación, desglosaremos cómo extraer y manipular los distintos componentes de una petición.
- Identificación del Método HTTP
El atributo method permite conocer el verbo HTTP utilizado por el cliente. Esto es fundamental para construir endpoints que respondan de manera diferente a peticiones GET, POST, PUT, etc.
from flask import Flask, request
app = Flask(__name__)
@app.route('/api/resource', methods=['GET', 'POST', 'PUT'])
def handle_resource():
http_method = request.method
print(f"Verbo HTTP recibido: {http_method}")
# Lógica condicional basada en el método
if http_method == 'POST':
return "Recurso creado", 201
return "Recurso obtenido", 200
- Extracción de Datos de Formularios
Cuando un cliente envía datos a través de un formulario HTML estándar (con Content-Type: application/x-www-form-urlencoded o multipart/form-data), los valores se almacenan en request.form. Este objeto es un ImmutableMultiDict, que se comporta de manera similar a un dicionario de Python, pero permite múltiples valores para una misma clave.
@app.route('/login', methods=['POST'])
def authenticate_user():
form_payload = request.form
# Acceso seguro usando .get() para evitar KeyError
username = form_payload.get('username')
password = form_payload['password'] # Lanza excepción si la clave no existe
# Obtener todas las claves enviadas
submitted_fields = list(form_payload.keys())
print(f"Campos en el formulario: {submitted_fields}")
# Conversión a un diccionario estándar de Python
# Nota: Si hay claves duplicadas, to_dict() conservará solo el primer valor
standard_dict = form_payload.to_dict()
- Parámetros de Consulta en la URL
Los parámetros enviados a través de la cadena de consulta (query string) en la URL, típicamente asociados a peticiones GET, se acceden mediante request.args. Su estructura y comportamiento son idénticos a los de request.form.
@app.route('/search', methods=['GET'])
def search_catalog():
query_params = request.args
# Ejemplo de URL: /search?category=electronics&sort=price
category = query_params.get('category', 'all')
sort_by = query_params.get('sort', 'relevance')
print(f"Parámetros de consulta: {list(query_params.items())}")
# Conversión a diccionario
params_dict = query_params.to_dict()
- Combinación de Parámetros (URL y Formulario)
Si necesitas acceder tanto a los parámetros de la URL como a los datos del formulario simultáneamente sin ipmortar su origen, request.values fusiona ambos en un CombinedMultiDict.
@app.route('/process', methods=['POST'])
def process_mixed_data():
# Combina request.args y request.form
all_parameters = request.values
# ADVERTENCIA: Si existe una clave duplicada entre la URL y el formulario,
# el valor de la URL (GET) sobrescribirá al del formulario (POST).
# Ejemplo: /process?token=abc (y token=xyz en el form) -> all_parameters['token'] será 'abc'
unified_dict = all_parameters.to_dict()
print(f"Datos unificados: {unified_dict}")
- Lectura de Cookies
Las cookies almacenadas en el navegador del cliente y enviadas en la cabecera de la petición se pueden leer mediante un diccionario estándar a través de request.cookies.
@app.route('/dashboard')
def user_dashboard():
session_token = request.cookies.get('session_token')
user_preferences = request.cookies.get('theme', 'light')
if not session_token:
return "Acceso denegado", 401
- Inspección de Encabezados (Headers)
Para acceder a los metadatos de la petición, como el User-Agent, tipos de contenido aceptados o tokens de autorización, se utiliza request.headers. Es un objeto iterable que permite búsquedas insensibles a mayúsculas y minúsculas.
@app.route('/inspect')
def inspect_headers():
user_agent = request.headers.get('User-Agent')
auth_token = request.headers.get('Authorization')
# Iterar sobre todos los encabezados
for header_key, header_value in request.headers:
print(f"{header_key}: {header_value}")
- Cuerpo de la Petición en Bruto (Raw Data)
Si el Content-Type de la petición no es reconocido nativamente por Flask (como texto plano, XML o tipos MIME personalizados), el cuerpo de la solicitud se almacena como una cadena de bytes en request.data.
import json
@app.route('/webhook', methods=['POST'])
def handle_webhook():
raw_body = request.data
# Si el payload es un JSON enviado con un Content-Type no estándar
try:
parsed_payload = json.loads(raw_body)
except (ValueError, TypeError):
parsed_payload = raw_body.decode('utf-8')
- Gestión de Carga de Archivos
Los archivos subidos mediante un formulario con enctype="multipart/form-data" se almacenan en request.files. Flask encapsula estos archivos en objetos FileStorage, lo que facilita su lectura y almacenamiento en disco.
import os
from werkzeug.utils import secure_filename
@app.route('/upload', methods=['POST'])
def upload_document():
if 'attachment' not in request.files:
return "No se encontró la parte del archivo", 400
uploaded_file = request.files['attachment']
if uploaded_file.filename != '':
# Sanitizar el nombre del archivo por seguridad
safe_filename = secure_filename(uploaded_file.filename)
save_path = os.path.join('/var/app/uploads', safe_filename)
# Guardar el archivo en el sistema
uploaded_file.save(save_path)
return f"Archivo {safe_filename} guardado exitosamente", 200
- Propiedades de Rutas y URLs
El objeto request expone diversas propiedades para reconstruir o analizar la estructura de la URL solicitada, lo cual es útil para generar enlaces dinámicos o redirecciones.
@app.route('/api/v1/users')
def show_url_properties():
endpoint_path = request.path # '/api/v1/users'
base_url = request.url_root # 'http://localhost:5000/'
full_url = request.url # 'http://localhost:5000/api/v1/users?filter=active'
script_root = request.script_root # '' (o el prefijo de la aplicación si está montada en un subdirectorio)
- Procesamiento de Cargas Útiles JSON
Para las APIs REST modernas que envían datos con Content-Type: application/json, Flask ofrece métodos dedicados para parsear automáticamente el cuerpo de la petición. Se recomienda usar get_json() en lugar de la propiedad json para tener un mejor control sobre el manejo de errores.
@app.route('/api/data', methods=['POST'])
def process_json_payload():
# silent=True evita lanzar una excepción 400 Bad Request si el JSON es inválido
json_data = request.get_json(silent=True)
if json_data is None:
return "El cuerpo de la petición no es un JSON válido", 400
action = json_data.get('action')
metadata = json_data.get('metadata', {})