Explorando el Objeto Request en Flask para Manejar Solicitudes HTTP

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.

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

  1. 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()

  1. 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()

  1. 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}")

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

  1. 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}")

  1. 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')

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

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

  1. 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', {})

Etiquetas: Flask Python werkzeug http-requests backend-development

Publicado el 10-20 22:04