Introducción a Requests y APIs REST
En el mundo actual de la programación, la comunicación entre aplicaciones es fundamental. Las APIs REST (Representational State Transfer) se han convertido en el estándar para la comunicación entre servicios web, y Python con la biblioteca Requests es la herramienta perfecta para interactuar con ellas de manera eficiente y sencilla.
¿Qué es una API REST?
Una API REST es una interfaz de programación de aplicaciones que sigue los principios de la arquitectura REST. Permite que dos sistemas se comuniquen a través del protocolo HTTP, utilizando los métodos estándar del protocolo para realizar operaciones sobre recursos.
Las APIs REST se caracterizan por:
- Comunicación sin estado: Cada petición contiene toda la información necesaria para procesarla.
- Uso de recursos: Todo se representa como recursos con URLs únicas.
- Métodos HTTP estándar: GET, POST, PUT, PATCH, DELETE.
- Formato de datos: Generalmente JSON o XML.
Instalación de la Biblioteca Requests
Antes de comenzar, necesitas instalar la biblioteca Requests. Esta es una de las librerías más populares de Python y se instala fácilmente con pip:
pip install requests
Una vez instalada, puedes importarla en tu script:
import requests
Métodos HTTP Fundamentales
Los métodos HTTP son las acciones que puedes realizar sobre los recursos de una API. Vamos a explorar los más importantes:
Método GET
El método GET se utiliza para obtener datos de un servidor. Es el método más común y seguro, ya que no modifica ningún recurso.
import requests
# Realizar una petición GET simple
respuesta = requests.get('https://api.ejemplo.com/usuarios')
# Verificar el código de estado
print(f'Código de estado: {respuesta.status_code}')
# Acceder al contenido JSON
datos = respuesta.json()
print(datos)
Nota: Un código de estado 200 indica éxito, 404 significa recurso no encontrado, y 500 indica error del servidor.
Método POST
El método POST se utiliza para crear nuevos recursos en el servidor.
import requests
# Datos a enviar
nuevo_usuario = {
'nombre': 'María García',
'email': '[email protected]',
'edad': 28
}
# Realizar petición POST
respuesta = requests.post(
'https://api.ejemplo.com/usuarios',
json=nuevo_usuario
)
print(f'Código: {respuesta.status_code}')
print(f'Respuesta: {respuesta.json()}')
# El parámetro json= automáticamente:
# - Serializa el diccionario a JSON
# - Establece el header 'Content-Type' a 'application/json'
Métodos PUT y PATCH
PUT reemplaza completamente un recurso, mientras que PATCH lo modifica parcialmente.
# PUT - Reemplaza todos los campos del usuario
respuesta_put = requests.put(
'https://api.ejemplo.com/usuarios/123',
json={'nombre': 'María López', 'email': '[email protected]', 'edad': 29}
)
# PATCH - Actualiza solo el campo necesario
respuesta_patch = requests.patch(
'https://api.ejemplo.com/usuarios/123',
json={'edad': 29}
)
Método DELETE
El método DELETE elimina un recurso del servidor.
respuesta = requests.delete('https://api.ejemplo.com/usuarios/123')
if respuesta.status_code == 204:
print('Usuario eliminado correctamente')
elif respuesta.status_code == 404:
print('El usuario no existe')
Manejo de Encabezados y Parámetros
Las APIs frecuentemente requieren encabezados personalizados para funcionar correctamente:
import requests
# Encabezados personalizados
headers = {
'Authorization': 'Bearer tu_token_de_acceso',
'Accept': 'application/json',
'User-Agent': 'MiApp/1.0'
}
# Parámetros de consulta (query parameters)
parametros = {
'pagina': 1,
'por_pagina': 20,
'orden': 'fecha_desc'
}
respuesta = requests.get(
'https://api.ejemplo.com/productos',
headers=headers,
params=parametros
)
print(respuesta.url)
# Resultado: https://api.ejemplo.com/productos?pagina=1&por_pagina=20&orden=fecha_desc
Autenticación con APIs
La autenticación es crucial para proteger tus APIs. Existen varios métodos comunes:
# Autenticación Basic Auth
from requests.auth import HTTPBasicAuth
respuesta = requests.get(
'https://api.ejemplo.com/datos-protegidos',
auth=HTTPBasicAuth('usuario', 'contraseña')
)
# Autenticación con Token Bearer (más común)
headers = {
'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
}
respuesta = requests.get(
'https://api.ejemplo.com/perfil',
headers=headers
)
Manejo de Errores y Excepciones
Es fundamental manejar correctamente los errores en tus peticiones:
import requests
from requests.exceptions import ConnectionError, Timeout, HTTPError
url = 'https://api.ejemplo.com/recurso'
try:
respuesta = requests.get(url, timeout=10)
respuesta.raise_for_status() # Lanza HTTPError si el código es 4xx o 5xx
datos = respuesta.json()
print(f'Éxito: {datos}')
except ConnectionError:
print('Error: No se pudo conectar al servidor')
except Timeout:
print('Error: La petición tardó demasiado tiempo')
except HTTPError as e:
print(f'Error HTTP: {e}')
except ValueError:
print('Error: La respuesta no es JSON válido')
Proyecto Práctico: Monitor de Estado de Servicios
Vamos a crear un monitor de estado que verifique la disponibilidad de varios servicios web:
import requests
from datetime import datetime
def verificar_servicio(nombre, url):
"""Verifica el estado de un servicio web."""
try:
respuesta = requests.get(url, timeout=5)
estado = '✓ Disponible' if respuesta.ok else '✗ Error'
tiempo = respuesta.elapsed.total_seconds()
return {
'servicio': nombre,
'estado': estado,
'tiempo_respuesta': f'{tiempo:.3f}s',
'codigo': respuesta.status_code
}
except Exception as e:
return {
'servicio': nombre,
'estado': '✗ No disponible',
'tiempo_respuesta': 'N/A',
'error': str(e)
}
# Lista de servicios a monitorear
servicios = [
('GitHub', 'https://api.github.com'),
('JSONPlaceholder', 'https://jsonplaceholder.typicode.com'),
('Dog CEO', 'https://dog.ceo/api/breeds/list/all')
]
print(f'\n{'='*60}')
print(f'Monitor de Servicios - {datetime.now().strftime("%Y-%m-%d %H:%M:%S")}')
print(f'{'='*60}\n')
for nombre, url in servicios:
resultado = verificar_servicio(nombre, url)
print(f"{resultado['servicio']:20} | {resultado['estado']:15} | {resultado['tiempo_respuesta']:10}")
print(f'{'='*60}\n')
Ejemplo: Consumir la API de OpenWeatherMap
Un ejemplo completo que consume una API real con clave de autenticación:
import requests
def obtener_clima(ciudad, api_key):
"""Obtiene el clima actual de una ciudad usando OpenWeatherMap API."""
base_url = 'https://api.openweathermap.org/data/2.5/weather'
parametros = {
'q': ciudad,
'appid': api_key,
'units': 'metric',
'lang': 'es'
}
respuesta = requests.get(base_url, params=parametros)
if respuesta.status_code == 200:
datos = respuesta.json()
return {
'ciudad': datos['name'],
'pais': datos['sys']['country'],
'temperatura': datos['main']['temp'],
'descripcion': datos['weather'][0]['description'].capitalize(),
'humedad': datos['main']['humidity'],
'viento': datos['wind']['speed']
}
elif respuesta.status_code == 401:
return {'error': 'API key inválida'}
elif respuesta.status_code == 404:
return {'error': f'Ciudad "{ciudad}" no encontrada'}
else:
return {'error': f'Error: {respuesta.status_code}'}
# Uso de la función
resultado = obtener_clima('Madrid', 'tu_api_key_aqui')
if 'error' in resultado:
print(resultado['error'])
else:
print(f"""
Clima en {resultado['ciudad']}, {resultado['pais']}
{'─'*35}
🌡️ Temperatura: {resultado['temperatura']}°C
☁️ Condición: {resultado['descripcion']}
💧 Humedad: {resultado['humedad']}%
💨 Viento: {resultado['viento']} m/s
""")
Errores Comunes
Al trabajar con Requests y APIs, estos son los errores que más frecuentemente встречаются:
-
No verificar el código de estado: Muchos programadores ignoran el status_code y asumen que todas las peticiones son exitosas. Siempre usa
respuesta.raise_for_status()o verifica el código antes de procesar los datos.
Incorrecto:datos = respuesta.json()
Correcto:respuesta.raise_for_status(); datos = respuesta.json() -
Olvidar el timeout: Sin un tiempo de espera, tu programa puede quedar indefinidamente esperando una respuesta. Siempre establece un
timeoutrazonable (generalmente entre 5 y 30 segundos). -
No manejar excepciones: Las conexiones de red fallan frecuentemente. Ignorar las excepciones
ConnectionError,TimeoutyHTTPErrorcausará que tu programa se bloquee inesperadamente. Usa bloquestry-exceptpara un código robusto.
Checklist de Dominio
Antes de continuar, verifica que dominas los siguientes conceptos:
- ✓ Instalar e importar la biblioteca Requests
- ✓ Realizar peticiones GET y acceder a datos JSON
- ✓ Enviar datos con el método POST usando el parámetro
json= - ✓ Utilizar PUT y PATCH para actualizar recursos
- ✓ Eliminar recursos con el método DELETE
- ✓ Enviar encabezados personalizados y parámetros de consulta
- ✓ Implementar autenticación (Basic Auth y Bearer Token)
- ✓ Manejar errores y excepciones apropiadamente
- ✓ Usar el parámetro timeout para evitar esperas infinitas
- ✓ Verificar códigos de estado con raise_for_status()
Con estos conocimientos, estás preparado para automatizar la comunicación con cualquier API REST desde Python. En la siguiente lección, profundizaremos en técnicas avanzadas como sesiones persistentes, reintentos automáticos y manejo de rate limiting.