Vamos a crear un API REST muy sencillo con Python. Para ello utilizaremos una librería llamada Flask.
Flask es un
microframework web para Python basado en Werkzeug
y Jinja 2 que nos provee de funcionalidades para construir
aplicaciones web, manejo de peticiones
HTTP con un enrutado sencillo para generar una API muy ligera y renderizado
de templates.
Se pueden utilizar
multitud de frameworks para crear aplicaciones web y APIs con Python. La más
conocida es Django, un framework muy
completo que te genera la estructura del proyecto y que incluye muchos plugins
y herramientas. Sin embargo para aplicaciones sencillas puede llegar a ser
abrumador y Flask es capaz de armar una API sencilla en un único fichero de
texto.
1. Primeros pasos
Lo primero que debemos
hacer es comprobar que tenemos Python instalado. Abrimos un terminal y
ejecutamos:
python --version
En caso de estar
instalado, la consola nos devolverá la versión de Python. En caso contrario,
debemos instalarlo.
Python 3.6.5
Ahora instalaremos Flask
utilizando pip, el gestor de paquetes
de Python.
pip install flask
A continuación será
necesario crearnos un directorio, una carpeta, para el proyecto.
Como soy poco
imaginativo, llamaré al proyecto “peliculas”, porque la API será de películas.
Dentro crearemos un
fichero vacío y lo llamaremos “api.py”.
De tal manera que
quedará:
peliculas/api.py
Ya tenemos todo listo
para empezar a darle caña a Python.
2. Creando la
app y el primer servicio tontorrón
Abrimos nuestro fichero
en blanco “api.py” y le copiamos el siguiente código. No os
preocupéis, lo explicaré a fondo más adelante.
import flask
app = flask.Flask(__name__)
app.config["DEBUG"]
= True
@app.route('/', methods=['GET'])
def home():
return "<h1>Mi
app de Pelis</h1><p>Este es mi sitio web super molón de películas
de los 90.</p>"
app.run()
Y voila, ya has creado
una aplicación en python. De momento sólo tiene un servicio, habrá que seguir
trabajando en ella.
·
Probando
los avances:
Para que todo esto
funcione debemos ejecutar nuestro archivo de Python. Para ello, volvemos a
nuestro terminal abierto, nos situamos en el archivo del proyecto y lanzamos el
proceso, como cualquier script de Python, escribiendo:
python api.py
El terminal nos debe
devolver algo como:
* Running
on http://127.0.0.1:5000/ (Press CTRL+C to quit)
¿Qué sucede ahora? Que
podemos invocar esa url con un método get desde Postman, o simplemente entrar a
un navegador, el Chrome por ejemplo, el que utilices por defecto, y acceder a
esta url.
o
http://127.0.0.1 hace referencia
a nuestro entorno local. De hecho, puede sustituirse por localhost: localhost:5000
o
:500 hace referencia al puerto
donde estamos escuchando las peticiones HTTP a nuestra API
Enhorabuena, parece
que todo ha ido bien.
·
¿Qué hace
mi código?
Vamos a explicar que está
ocurriendo aquí:
Primero se importa la
librería de flask, esto quiere decir, que tendremos acceso desde nuestro
proyecto a todo el código de esta librería, que hará el trabajo sucio por
nosotros.
import flask
Flask está mapeando las
peticiones HTTP a funciones de Python. En este caso, hemos mapeado el path “/” a la función home.
@app.route('/', methods=['GET'])
def home():
return "<h1>Mi
app de Pelis</h1><p>Este es mi sitio web super molón de películas
de los 90.</p>"
Cuando nos conectamos a http://127.0.0.1:5000/, lo cual es la url donde lanzamos el proyecto (http://127.0.0.1:5000)
más el path (/) al que lanzamos la petición, Flask mira a ver si el path
solicitado coincide con alguno de los declarados. Como hemos declarado el path
“/” Flask lo localiza y ejecuta la función home,
la cual devuelve un par de líneas html renderizadas.
A todo este proceso se le
llama enrutamiento, o routing.
app = flask.Flask(__name__)
app.config["DEBUG"]
= True
Lo que ocurre en estas líneas
es sencillo. Flask crea el objeto aplicación como la variable global app. Este objeto contiene toda la
información y los métodos que hacen que la aplicación realice diferentes
acciones. Por ejemplo, la última línea de código app.run(), que le indica a la aplicación que debe iniciarse, es uno
de estos métodos.
En la segunda de estas
líneas se especifica que la aplicación debe iniciarse en modo debug. De esta manera se nos informará
desde el terminal de cualquier error o información extra. Muy útil en
desarrollo, pero que debemos deshabilitar a la hora de subir nuestra aplicación
a producción.
Ahora que sabemos cómo
arrancar la aplicación y crear servicios, vamos a intentar que nuestra API
sirva para algo.
3. Devolviendo
datos desde la API
La principal función de
una API es la de proveer información a los clientes que la invocan. Esta
información no es más que datos persistentes almacenados en una base de datos o
consultados en otra API, pudiendo sufrir transformaciones, dependiendo de las exigencias
del servicio. También en algunos casos, se crean servicios para que los
clientes puedan modificar dicha información.
Vamos a hacer un pequeño
ejemplo de cómo nuestra API puede suministra datos mediante una llamada GET.
De momento ni siquiera vamos
a consultar base de datos. Vamos a añadir nuestros datos a una lista de
diccionarios de Python, que no son más que objetos con un par de clave (key) –
valor (value). Algo así:
{
'key1': 'value1',
'key2': 'value2'
{
Siguiendo la ingeniosa
idea de las pelis, nuestro array de diccionarios podría ser el siguiente:
[
{
'title': 'Pulp Fiction',
'author': 'Quentin Tarantino'
{
'title': 'Die Hard 3',
'author': 'John McTiernan'
}
]
Vamos a añadir esta
información dentro de nuestro fichero api.py, la enriqueceremos un poco y la
asignaremos a una variable. También crearemos un par de métodos para que pueda
ser consultada.
Nuestro código ahora, sería el siguiente:
import flask
from flask import request, jsonify
app = flask.Flask(__name__)
app.config["DEBUG"]
= True
films = [
{'id': 0,
'title': 'Pulp Fiction',
'author': 'Quentin Tarantino',
'year_published': '1994'},
{'id': 1,
'title': 'Die Hard 3',
'author': 'John McTiernan',
'published': '1995'},
{'id': 2,
'title': 'Jurassic Park',
'author': 'Steven Spielberg',
'published': '1993'}
]
@app.route('/', methods=['GET'])
def home():
return "<h1>Mi
app de Pelis</h1><p>Este es mi sitio web super molón de películas
de los 90.</p>"
# A route to return
all of the available entries in our catalog.
@app.route('/api/films/all', methods=['GET'])
def api_all():
return jsonify(films)
@app.route('/api/films', methods=['GET'])
def api_id():
#
Check if an ID was provided as part of the URL.
#
If ID is provided, assign it to a variable.
#
If no ID is provided, display an error in the browser.
if 'id' in request.args:
id = int(request.args['id'])
else:
return "Error: No id
field provided. Please specify an id."
#
Create an empty list for our results
results = []
#
Loop through the data and match results that fit the requested ID.
#
IDs are unique, but other fields might return many results
for film in films:
if film['id'] == id:
results.append(film)
#
Use the jsonify function from Flask to convert our list of
#
Python dictionaries to the JSON format.
return jsonify(results)
app.run()
Hemos implementado dos
nuevos servicios, uno para consultar todas las películas de nuestra aplicación,
y otro para consultar película por película indicando el id.
·
Probando
los avances:
Si ya tenemos el servidor
lanzado desde el terminal, Flask actualizará automáticamente los cambios al
guardarlos desde el editor, sin necesidad de reiniciar. En caso contrario,
tenemos que volver a lanzarlo como ya vimos en la sección anterior.
De igual manera que antes
hemos llamado a http://127.0.0.1:5000/ y nos devolvía el HTML de la home de nuestra
aplicación, ahora probaremos las siguientes llamadas:
o localhost:5000/api/films/all
Recordemos que localhost hace referencia a nuestro local, igual que
127.0.0.1
Al realizar un GET a esta dirección obtendremos el array de diccionarios
con toda la información de películas que tenemos almacenadas en nuestra app. Te
aconsejo que lo pruebes.
o localhost:5000/api/films?id=0
Si hacemos GET sobre esta url, nos devolverá únicamente la información
correspondiente a la película almacenada con id igual a 0, en este caso, Pulp
Fiction.
Ahora prueba a cambiar el valor del id en la url y verás como la
información que nos llega va cambiando. ¿Qué pasaría si pedimos el id = 3? ¿Por
qué?
·
¿Qué hace
mi código?
El primero de los
servicios es muy sencillo. Nueva ruta, nueva función que devuelve información
almacenada en la variable films, el
diccionario con todas las películas, declarada mas arriba.
@app.route('/api/films/all', methods=['GET'])
def api_all():
return jsonify(films)
Lo único novedoso es jsonify, que es una función que
transforma nuestros objetos de Python a formato JSON, que es un formato de
transferencia de datos.
El segundo servicio tiene
un poquito más miga. Entra en juego el objeto request que nos permite acceder a la información de la llamada
entrante, entre otras cosas los parámetros que le pasamos a la llamada,
cabeceras, cuerpo de la llamada si lo hubiera, etc.
Tanto jsonify como request han sido importados de la librería flask al principio del
código.
Así pues, esto nos
permite acceder a la información almacenada en request.args que no es otra que la que hemos introducido en la url
detrás del símbolo “?”, los argumentos de la llamada. Vamos a verlo en el
código.
if 'id' in request.args:
id = int(request.args['id'])
else:
return "Error: No id
field provided. Please specify an
id."
En request.args esperamos encontrar una varliable llamda id para asignarle el valor a nuestra
variable id. En caso contrario, devolveríamos un mensaje de error.
Posteriormente
recorreremos nuestros datos con un bucle for,
nos quedaremos con el elemento cuyo id coincida, lo añadiremos a results y lo
devolveremos con un return como un
objeto JSON.
Hemos completado la parte
primera del curso. Puedes descargar aquí todo el código que hemos escrito y
probarlo.
Siguiente misión: Añadir
conexión a Base de Datos.