API es la Application Programming Interface, es decir nuestra forma de interactuar con una aplicación. REST quiere decir REpresentational State Transfer. Normalmente cuando hablamos de REST, estamos hablando de una interfaz para obtener datos usando directamente HTTP, es decir es un tipo de web API.
De manera sencilla podemos decir que es una Interfaz con la que se interactúa mediante URLs normalmente para obtener datos.
La principal diferencia entre esto y una URL común, es que la URL de una página web devolverá algo que tu navegador puede interpretar y mostrar de forma "bonita", mientras que una API web mandará datos o instrucciones útiles para ti o tu ordenador.
In [1]:
# preserve
from IPython.display import HTML
Veamos la respuesta a una página web clásica
In [2]:
HTML('<iframe src="https://developer.github.com/v3/" width="700" height="400"></iframe>')
Out[2]:
Veamos la respuesta de una web api
In [3]:
HTML(url="https://api.github.com/")
Out[3]:
En definitiva, cuando utilizamos una WEB API, están involucrados:
El uso de WEB APIs permite: obtener información que sería cosotsa de obtener y procesar de otra manera (incluso en tiempo real).
En algunas ocasiones, la API es pública y cualquiera puede hacer una petición, pero en otras es necesario tener una api key que nos identifica. Por lo tanto, el proceso para obtener datos suele ser:
Esta es la página principal de su API:
https://opendata.aemet.es/centrodedescargas/inicio
Aquí podemos encontrar: información general, el lugar donde obtener nuestra API key, una interfaz para acceder a los datos para público general
In [4]:
HTML('<iframe src="https://opendata.aemet.es/centrodedescargas/inicio" width="1000" height="400"></iframe>')
Out[4]:
Aunque existen otras formas y librería para trabajar con HTTP en Python, el módulo requests
está específicamente pensado para trabajar con APIs web.
Como siempre hasta ahora, lo primero es importarlo:
In [5]:
import requests
Necesitaremos cargar nuesta API key, lo más cómodo es almacenarla en un fichero y cargarla desde ahí. Creemos una función para leerla:
In [6]:
# preserve
def load_api_key(file):
"""Returns the contents in the file without the final line break
"""
with open(file, 'r') as f:
api_key = f.read().rstrip()
return api_key
In [7]:
# cargamos la api_key
api_key = load_api_key("../../apikey-aemet.txt")
Debemos saber cuál es la url a la que vamos a hacer la petición:
In [8]:
# Fijamos la url y los parámetros
# Predicción costera de Asturias, Cantabria y País Vasco debemos introducir
# https://opendata.aemet.es/opendata/api/prediccion/maritima/costera/costa/41
url = "https://opendata.aemet.es/opendata/api/prediccion/maritima/costera/costa/41"
querystring = {"api_key": api_key}
Por último, lanzamos la petición:
In [9]:
# Lanzamos la request
response = requests.get(url, params=querystring, verify=False)
Comprobando la respuesta:
In [10]:
# Vemos la respuesta
response
Out[10]:
Vemos que hemos obtenido una respuesta con código 200, esto quiere decir, en el código habitual de las API-REST, que todo ha ido bien. De hecho, es conveniente ver que todo ha ido bien antes de hacer nada más:
In [11]:
# código de estado
response.status_code == requests.codes.ok
Out[11]:
Otra información que podemos obtener es, por ejemplo;
In [12]:
# preserve
# Tiempo en procesar la petición
print("Elapsed: ", response.elapsed)
# Información del servidor
print("Headers: ", response.headers)
Pero... ¿dónde están nuestros datos?
In [13]:
response.content
Out[13]:
¡Parece que esto es un json!
In [14]:
content = response.json()
content
Out[14]:
Efectivamente, la mayoría de las WEB APIs devuelven json o xml. Pero, otra vez... ¿dónde están nuestros datos?
In [15]:
r_meta = requests.get(content['metadatos'], verify=False)
r_data = requests.get(content['datos'], verify=False)
if r_meta.status_code == requests.codes.ok:
metadata = r_meta.json()
if r_data.status_code == requests.codes.ok:
data = r_data.json()
In [16]:
print(metadata[0].keys())
print(data[0].keys())
In [17]:
metadata[0]['periodicidad']
Out[17]:
In [18]:
data[0]['prediccion']
Out[18]:
En definitiva, podríamos reagrupar todo lo anterior como:
In [19]:
# preserve
from warnings import warn
def get_prediction_for_cantabria(api_key):
url = "https://opendata.aemet.es/opendata/api/prediccion/maritima/costera/costa/41"
querystring = {"api_key": api_key}
response = requests.get(url, params=querystring, verify=False)
prediction = None
if response.status_code == requests.codes.ok:
r_data = requests.get(content['datos'], verify=False)
if r_data.status_code == requests.codes.ok:
data = r_data.json()
prediction = data[0]['prediccion']
elif response.status_code == requests.codes.TOO_MANY_REQUESTS:
warn('Too many requests')
elif response.status.code == requests.codes.NOT_FOUND:
warn('No data for the response')
else:
warn('Code error {}'.format(response.status_code))
return prediction