APIs Web, Peticiones en Python y Realización de una Petición HTTP en el Tutorial de Python
Practica realizando una petición HTTP en Python con este ejercicio práctico.
Las interfaces de programación de aplicaciones (API) son mediadores de softwaresu función es permitir que las aplicaciones se comuniquen entre sí. Estos mediadores sutiles aparecen en la vida cotidiana, lo sepas o no. Por ejemplo, si hoy has enviado un mensaje instantáneo, has utilizado una API.
Más concretamente, las API permiten enviar y recuperar datos mediante código. Sin embargo, es más habitual utilizar API para recuperar datos; por ejemplo, puedes leer esta entrada del blog porque tu navegador web recuperó del servidor de DataCamp los datos que componen esta página.
Pero los servidores web no envían datos al azar, eso sería como ir a un restaurante y que el camarero te trajera la comida al azar. Hay que hacer una petición al servidor para recuperar datos antes de que responda con datos. Esto es válido para el camarero de un restaurante, y si quieres recuperar algún dato de una API: haces una petición de API a un servidor, y éste responderá con los datos apropiados.
El estándar industrial de facto para enviar peticiones HTTP en Python es la biblioteca requests. También existe la función urllibde Python, pero los pythonistas suelen preferir la API de peticiones de Python por su facilidad de lectura y por el hecho de que es totalmente compatible con las APIs restful, algo a lo que nos referiremos más adelante.
La biblioteca de peticiones aísla todos los retos de hacer peticiones detrás de una API sencilla, lo que te permite concentrarte en comunicarte con los servicios y consumir datos en tu aplicación.
En este artículo, recorreremos algunos de los componentes básicos de la biblioteca de peticiones y proporcionaremos algunos ejemplos de código para ayudarte a empezar.
Ejecute y edite el código de este tutorial en línea
Ejecutar códigoAPI REST
Hemos establecido que las API son mediadores de software. Otra forma de pensar en ellos es como un tipo de interfaz de software que concede a otras aplicaciones acceso a datos y métodos específicos.
Una de las arquitecturas más utilizadas para construir APIs es el patrón REpresentational State Transfer (REST). El diseño arquitectónico REST permite que el cliente y el servidor se implementen independientemente el uno del otro sin ser conscientes el uno del otro - esto significa que el código de cualquiera de los dos lados puede cambiarse sin preocuparse de cómo afectará el cambio al otro.
Son un conjunto de directrices diseñadas para simplificar las comunicaciones entre programas informáticos, haciendo así más sencillo y lógico el proceso de acceso a los datos. No te preocupes si no conoces estas directrices; no necesitas conocerlas para empezar; lo que sí necesitas saber es cómo se exponen los datos desde los servicios REST.
Los datos de los servicios web REST se exponen a Internet a través de una URL pública, a la que se puede acceder enviando una petición HTTP.
Métodos HTTP
Volvamos a nuestra analogía del restaurante: para pedir comida en un restaurante, el camarero se acercará a ti y tú le dirás lo que quieres. A continuación, el camarero pasa tu pedido al cocinero, que prepara la comida y se la pasa al camarero para que te la devuelva. En otras palabras, el cocinero no cocinaría tu comida hasta que se hubiera enviado tu solicitud.
Las API REST son iguales: escuchan los métodos de petición HTTP antes de realizar ninguna acción. HTTP es lo que define un conjunto de métodos de solicitud para indicar a la API qué operaciones debe realizar con un recurso determinado. Especifica cómo interactuar con los recursos situados en el punto final proporcionado.
Existen varios métodos HTTP, pero cinco se utilizan habitualmente con las API REST:
Método HTTP |
Descripción |
OBTENER |
Recuperar datos |
POST |
Crear datos |
PUT |
Actualiza los datos existentes |
PATCH |
Actualizar parcialmente los datos existentes |
BORRAR |
Borrar datos |
Es muy probable que realices solicitudes GET más que cualquier otro método en el análisis y la ciencia de datos. Esto se debe a que es el método más necesario para acceder a determinados conjuntos de datos: aprende a hacerlo con el curso Intermedio de Importación de Datos en Python de DataCamp.
Cuando realizas una petición a un servidor web, la API devuelve una respuesta. A la respuesta se adjunta un código de estado HTTP. La finalidad del código de estado es proporcionar información adicional sobre la respuesta, para que el cliente sepa el tipo de solicitud que está recibiendo.
Nota: Más información sobre los Códigos de Estado.
Puntos finales
Los datos con los que interactúas en un servidor web se delimitan con una URL. Al igual que la URL de una página web está conectada a una sola página, la URL de un punto final está conectada a recursos concretos dentro de una API. Por tanto, un punto final puede describirse como una ubicación digital en la que una API recibe consultas sobre un recurso concreto en su servidor: piensa en él como el otro extremo de un canal de comunicación.
Para añadir más contexto, las API REST exponen un conjunto de URL públicas que pueden solicitar las aplicaciones cliente para acceder a los recursos del servicio web. Las URL públicas expuestas por la API REST se conocen como "puntos finales".
Utilizar Python para consumir APIs
La API de peticiones de Python permite a los desarrolladores escribir código para interactuar con las API REST. Les permite enviar peticiones HTTP utilizando Python sin tener que preocuparse de las complejidades que suelen conllevar estas tareas (es decir, añadir manualmente cadenas de consulta a las URL, codificación de formularios...). PUT
y POST
data, etc.).
A pesar de ser considerado el estándar de facto para realizar peticiones HTTP en Python, el método requests
no forma parte de la biblioteca estándar de Python, por lo que debes instalarlo.
La forma más sencilla de instalar el módulo de peticiones es con pip:
python -m pip install requests
Siempre es recomendable gestionar los paquetes de Python necesarios para los distintos proyectos en entornos virtuales; de este modo, los paquetes de un proyecto no interferirán ni romperán las herramientas del sistema en otros proyectos, porque están aislados, en lugar de instalarse globalmente.
Ahora que ya tenemos instalado el módulo de peticiones, veamos cómo funciona.
Hacer una petición GET
Ya hemos establecido que GET es uno de los métodos de solicitud HTTP más comunes que encontrarás cuando trabajes con API REST. Te permite (al cliente) recuperar datos de servidores web.
Algo importante a tener en cuenta es que GET es una operación de sólo lectura, lo que significa que sólo es adecuada para acceder a los recursos existentes, pero no debe utilizarse para modificarlos.
Para demostrar cómo funciona el módulo de solicitud, utilizaremos JSONPlaceholder, que es una API falsa de libre acceso utilizada para pruebas y prototipos.
Sigue el código en este Espacio de trabajo DataCamp.
import requests
# The API endpoint
url = "https://jsonplaceholder.typicode.com/posts/1"
# A GET request to the API
response = requests.get(url)
# Print the response
response_json = response.json()
print(response_json)
"""
{'userId': 1, 'id': 1, 'title': 'sunt aut facere repellat provident occaecati excepturi optio reprehenderit', 'body': 'quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto'}
"""
En el código anterior, realizamos lo siguiente:
- Definido el punto final de la API para recuperar datos de
- Utiliza el
requests.get(url)
para recuperar los datos del punto final definido. - Utilizamos el
response.json()
para almacenar los datos de la respuesta en un objeto diccionario; ten en cuenta que esto sólo funciona porque el resultado se escribe en formato JSON; de lo contrario, se habría producido un error. - El último paso es imprimir los datos de la respuesta JSON.
También podemos comprobar así el código de estado devuelto por la API:
# Print status code from original response (not JSON)
print(response.status_code)
"""
200
"""
También puedes pasar argumentos a una petición GET de Python. Para ello, debemos modificar ligeramente el código anterior. Este es el aspecto del nuevo código...
# The API endpoint
url = "https://jsonplaceholder.typicode.com/posts/"
# Adding a payload
payload = {"id": [1, 2, 3], "userId":1}
# A get request to the API
response = requests.get(url, params=payload)
# Print the response
response_json = response.json()
for i in response_json:
print(i, "\n")
"""
{'userId': 1, 'id': 1, 'title': 'sunt aut facere repellat provident occaecati excepturi optio reprehenderit', 'body': 'quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto'}
{'userId': 1, 'id': 2, 'title': 'qui est esse', 'body': 'est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla'}
{'userId': 1, 'id': 3, 'title': 'ea molestias quasi exercitationem repellat qui ipsa sit aut', 'body': 'et iusto sed quo iure\nvoluptatem occaecati omnis eligendi aut ad\nvoluptatem doloribus vel accusantium quis pariatur\nmolestiae porro eius odio et labore et velit aut'}
"""
Esto es lo que hicimos de forma diferente:
- Cambiado el punto final de la API. Observa que ya no tiene un "1" al final.
- Define la carga útil en un diccionario.
- Pasa la carga útil al
param
argumento delrequests.get()
método. - Esto devuelve un objeto lista, así que recorremos la lista e imprimimos cada elemento en una nueva línea.
Hacer una petición POST
Las peticiones GET te permiten recuperar datos; las peticiones POST te permiten crear nuevos datos. Veamos cómo podemos crear nuevos datos en el servidor JSONPlaceholder.
# Define new data to create
new_data = {
"userID": 1,
"id": 1,
"title": "Making a POST request",
"body": "This is the data we created."
}
# The API endpoint to communicate with
url_post = "https://jsonplaceholder.typicode.com/posts"
# A POST request to tthe API
post_response = requests.post(url_post, json=new_data)
# Print the response
post_response_json = post_response.json()
print(post_response_json)
"""
{'userID': 1, 'id': 101, 'title': 'Making a POST request', 'body': 'This is the data we created.'}
"""
En el código anterior, realizamos lo siguiente:
- Hemos creado un nuevo recurso que queríamos añadir a la API JSONPlaceholder
- Definido el punto final para POSTULAR los nuevos datos
- Envía una petición POST utilizando la función
requests.post()
método. Ten en cuenta quejson
en el parámetropost()
para indicar a la API que estamos enviando explícitamente un objeto JSON a la URL especificada. - Utiliza el
response.json()
para almacenar los datos de la respuesta en un objeto diccionario - El último paso es imprimir los datos de la respuesta JSON.
¡ESPERA!
Antes de leer el siguiente fragmento de código, tómate 20 segundos para pensar qué código de estado podemos esperar que nos devuelva la API.
Recuerda que esta vez hemos creado un nuevo recurso en lugar de simplemente recuperarlo.
Vale, allá va...
# Print status code from original response (not JSON)
print(post_response.status_code)
"""
201
"""
¿Lo has hecho bien?
Temas avanzados
Autentificar solicitudes
Hasta ahora, las interacciones que hemos tenido con la API REST han sido bastante sencillas. La API de JSONPlaceholder no requiere ninguna autenticación para que puedas empezar a interactuar con ella. Pero hay varios casos en los que una API REST puede requerir autenticación antes de conceder acceso a puntos finales específicos, especialmente cuando se trata de datos sensibles.
Por ejemplo, si quieres crear integraciones, recuperar datos y automatizar tus flujos de trabajo en GitHub, puedes hacerlo con la API REST de GitHub. Sin embargo, hay muchas operaciones en la API REST de GitHub que requieren autenticación, como recuperar información pública y privada sobre usuarios autenticados.
Aquí tienes una solución sencilla utilizando el módulo de peticiones de Python:
from requests.auth import HTTPBasicAuth
private_url = "https://api.github.com/user"
github_username = "username"
token = "token"
private_url_response = requests.get(
url=private_url,
auth=HTTPBasicAuth(github_username, token)
)
private_url_response.status_code
"""
200
"""
En el código anterior
- Importado el
HTTPBasicAuth
objeto derequests.auth
; este objeto adjunta la autenticación básica HTTP al objeto de solicitud dado - es esencialmente lo mismo que escribir tu nombre de usuario y contraseña en un sitio web. - Definido el punto final de la URL privada para acceder
- Instanciamos una variable con un nombre de usuario de GitHub - anonimizamos el nombre de usuario por privacidad.
- Instancia de una variable GitHub con un token de acceso personal para la autenticación.
- Recuperamos los datos de nuestro endpoint y los almacenamos en el archivo
private_url_response
variable. - Muestra el código de estado.
Tratamiento de errores
Hay casos en los que las solicitudes realizadas a una API no salen como se esperaba. Pueden intervenir varios factores, tanto en el lado del cliente como en el del servidor. Independientemente de la causa, el resultado es siempre el mismo: la solicitud fracasa.
Cuando utilices API REST, siempre es una buena idea hacer que tu código sea resistente. Sin embargo, antes de poder escribir código robusto, debes comprender cómo gestionar los errores notificados cuando las cosas no salen según lo previsto.
Volvamos a la API JSONPlaceholder para esta demostración. Empezaremos escribiendo algo de código y luego explicaremos lo que ocurre.
# A deliberate typo is made in the endpoint "postz" instead of "posts"
url = "https://jsonplaceholder.typicode.com/postz"
# Attempt to GET data from provided endpoint
try:
response = requests.get(url)
response.raise_for_status()
# If the request fails (404) then print the error.
except requests.exceptions.HTTPError as error:
print(error)
"""
404 Client Error: Not Found for url: https://jsonplaceholder.typicode.com/postz
"""
En el código anterior
- Hemos definido el punto final del soporte JSONPlace para recuperar los datos, pero hemos cometido un error tipográfico deliberado al construir la URL: esto generará un error 404.
- Utiliza el manejo de excepciones integrado en Python, try y except para capturar cualquier error que se produzca al intentar visitar el punto final de JSONPlaceholder. Ten en cuenta que
raise_for_status()
es el que se utiliza para devolver un objeto HTTPError cuando se produce un error durante el proceso. - Imprime el error que se ha producido.
Aunque en este caso hemos demostrado cómo gestionar los códigos de estado de error 404, se puede utilizar el mismo formato para gestionar cualquier código de estado HTTP.
Hacer frente a demasiados redireccionamientos
Los códigos de estado HTTP con el formato 3xx indican que el cliente ha sido redirigido y debe realizar algunas acciones adicionales para completar la solicitud. Sin embargo, esto puede llevar ocasionalmente a situaciones en las que acabes con un bucle de redirección infinito.
El módulo requests de Python proporciona el objeto TooManyRedirects para gestionar este problema, como se indica a continuación:
"""
Note: The code here will not raise an error
but the structure is how you would hand a case where there
are multiple redirects
"""
url = "https://jsonplaceholder.typicode.com/posts"
try:
response = requests.get(url)
response.raise_for_status()
except requests.exceptions.TooManyRedirects as error:
print(error)
También puedes establecer el número máximo de redirecciones como parámetro de tu método de petición HTTP:
# Solution 2
url = "https://jsonplaceholder.typicode.com/posts"
session = requests.Session()
session.max_redirects = 3
response = session.get(url)
Otra opción es desactivar completamente las redirecciones:
# Solution 3
url = "https://jsonplaceholder.typicode.com/posts"
session = requests.Session()
session.allow_redirects = False
response = session.get(url)
Errores de conexión
Son otro tipo de error que puedes encontrarte al intentar enviar peticiones a un servidor. Hay varias razones por las que puedes no recibir una respuesta del servidor (por ejemplo, fallo de DNS, conexión rechazada, problemas de conexión a Internet, etc.), pero el resultado es el mismo: se produce un error de conexión.
Puedes utilizar el requests
ConnectionError para detectar estos problemas y tratarlos como corresponda.
Así es como quedaría el código
"""
Note: The code here will not raise an error
but the structure is how you would hand a case where there
is a connection error.
"""
url = "https://jsonplaceholder.typicode.com/posts"
try:
response = requests.get(url)
except requests.ConnectionError as error:
print(error)
Tiempo de espera
Cuando el servidor de la API acepta tu conexión pero no puede finalizar tu solicitud en el tiempo permitido, obtendrás lo que se conoce como un "error de tiempo de espera".
Demostraremos cómo tratar este caso estableciendo la opción timeout
en el parámetro requests.get()
a un número extremadamente pequeño; esto provocará un error y lo gestionaremos mediante el método requests.Timeout object
.
url = "https://jsonplaceholder.typicode.com/posts"
try:
response = requests.get(url, timeout=0.0001)
except requests.Timeout as error:
print(error)
La solución más sencilla para los errores de tiempo de espera es establecer tiempos de espera más largos. Otras soluciones pueden incluir la optimización de tus peticiones, la incorporación de un bucle de reintento en tus scripts o la realización de llamadas asíncronas a la API, una técnica que permite a tu software iniciar una actividad potencialmente de larga duración mientras responde a otros eventos, en lugar de tener que esperar hasta que se complete esa tarea.
Envolver
En este tutorial, hemos tratado qué son las API y hemos explorado una arquitectura de API común llamada REST. También hemos visto los métodos HTTP y cómo podemos utilizar la biblioteca de peticiones de Python para interactuar con los servicios web.
Echa un vistazo a los siguientes cursos para desarrollar tus habilidades en ciencia de datos:
Cursos de Python
Course
Introduction to Python
Course
Introduction to Data Science in Python
Course
Intermediate Python
tutorial
Tutorial de FastAPI: Introducción al uso de FastAPI
tutorial
Desarrollo de backend en Python: Guía completa para principiantes
Oluseye Jeremiah
26 min
tutorial
Datos JSON en Python
tutorial
Guía completa de programación de sockets en Python
Serhii Orlivskyi
41 min
tutorial
Programación orientada a objetos (POO) en Python: Tutorial
tutorial