Requests en Python: consumir APIs paso a paso

Aplicación Python intercambiando JSON con una API mediante Requests

La biblioteca Requests en Python simplifica el consumo de APIs HTTP. Permite enviar parámetros, cabeceras y cuerpos JSON, comprobar respuestas y mantener sesiones con una interfaz legible. Una integración profesional, sin embargo, necesita algo más que llamar a requests.get: debe controlar tiempos de espera, errores, reintentos, autenticación y validación de datos.

Instalar y hacer la primera petición

Instala la dependencia en un entorno virtual y fija una versión compatible en el archivo de dependencias:

python -m pip install requests

Una petición básica devuelve un objeto Response:

import requests

respuesta = requests.get(
    "https://api.ejemplo.com/v1/productos",
    params={"categoria": "libros", "limite": 20},
    timeout=10,
)
respuesta.raise_for_status()
datos = respuesta.json()

params construye y codifica la query string. Evita concatenar manualmente valores proporcionados por usuarios.

El timeout no es opcional

Requests no aplica un límite de tiempo global por defecto. Sin timeout, un proceso puede quedar esperando indefinidamente. Puedes proporcionar un número o una tupla para separar conexión y lectura:

timeout=(3.05, 20)

El límite no representa necesariamente la duración total de la descarga, sino los periodos de inactividad descritos por la biblioteca. Ajusta los valores a la latencia y al tamaño esperados.

Comprobar estados y contenido

raise_for_status lanza HTTPError ante respuestas 4xx o 5xx. Después, valida que el tipo de contenido y la estructura correspondan al contrato:

try:
    respuesta = requests.get(url, timeout=(3, 15))
    respuesta.raise_for_status()
    datos = respuesta.json()
except requests.Timeout:
    # registrar y decidir si reintentar
    raise
except requests.HTTPError as error:
    # conservar código y contexto sin exponer secretos
    raise
except requests.JSONDecodeError:
    # la respuesta no contiene JSON válido
    raise

No uses un except genérico que convierta todos los fallos en una lista vacía: mezclaría “sin resultados” con “servicio caído”.

GET, POST y cuerpos JSON

Para enviar JSON, utiliza el argumento json. Requests serializa el objeto y establece la cabecera apropiada:

nuevo = {"nombre": "Informe mensual", "estado": "borrador"}
respuesta = requests.post(
    "https://api.ejemplo.com/v1/informes",
    json=nuevo,
    timeout=10,
)

data se usa para formularios o cuerpos ya preparados. PUT suele reemplazar un recurso, PATCH modifica parcialmente y DELETE solicita su eliminación; la semántica final depende de la API.

Autenticación y secretos

Una API puede usar Basic Auth, tokens Bearer, OAuth u otros esquemas. No escribas tokens en el código ni los incluyas en URLs. Cárgalos desde un gestor de secretos o variables de entorno y evita registrarlos:

cabeceras = {"Authorization": f"Bearer {token}"}

Verifica siempre TLS. Desactivar verify elimina una protección esencial y no es una solución aceptable para certificados mal configurados.

Sessions, conexión y cabeceras comunes

Session reutiliza conexiones y permite definir cabeceras o cookies compartidas:

with requests.Session() as sesion:
    sesion.headers.update({"Accept": "application/json"})
    respuesta = sesion.get(url, timeout=10)

Esto reduce latencia en múltiples solicitudes al mismo servicio. Cierra la sesión con un bloque with y no compartas una sesión mutable entre hilos sin analizar su seguridad.

Reintentos responsables

Reintentar puede resolver fallos transitorios, pero repetir un POST no idempotente podría crear duplicados. Aplica reintentos limitados, espera exponencial y variación aleatoria únicamente a estados y métodos adecuados. Respeta Retry-After y los límites de la API.

El adaptador HTTPAdapter junto con urllib3 Retry permite centralizar la política. Registra el número de intentos y detén el proceso cuando el error no sea transitorio.

Paginación y límites

Muchas APIs devuelven páginas. Itera mediante el cursor o enlace next indicado por el servidor, limita el máximo de páginas y guarda checkpoints en procesos largos. Ante un 429, reduce el ritmo según las cabeceras del proveedor.

Diseño para producción

Encapsula la comunicación en una clase o función con una interfaz estable. Separa transporte, validación y lógica de negocio. Añade registros estructurados sin datos personales, métricas de latencia, pruebas con respuestas simuladas y una política de errores que el consumidor pueda entender.

Una integración fiable valida el esquema recibido antes de guardarlo. Las APIs evolucionan: campos opcionales pueden faltar, los tipos pueden cambiar y una respuesta 200 todavía puede contener datos inválidos para tu aplicación.

Continúa aprendiendo

Amplía este tema con nuestras guías sobre recopilar datos con APIs, recopilar datos con Python, APIs gratuitas para practicar.

Fuentes oficiales

Preguntas frecuentes

¿Para qué sirve Requests en Python?
Sirve para enviar peticiones HTTP y trabajar con parámetros, cabeceras, autenticación, cuerpos y respuestas mediante una API sencilla.

¿Por qué debo definir timeout?
Porque Requests no impone uno global por defecto y una conexión problemática podría bloquear el proceso durante demasiado tiempo.

¿Qué hace raise_for_status?
Lanza una excepción HTTPError cuando la respuesta contiene un código de error del cliente o del servidor.

¿Cuál es la diferencia entre json y data?
json serializa un objeto como JSON y establece la cabecera correspondiente; data se usa para formularios o cuerpos preparados.

¿Cuándo conviene usar Session?
Cuando haces varias peticiones al mismo servicio y quieres reutilizar conexiones, cabeceras, cookies o autenticación común.

¿Se deben reintentar todas las peticiones?
No. Solo fallos transitorios y operaciones seguras o idempotentes, con límites y espera progresiva para no generar duplicados ni sobrecarga.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Subir