Servicios web REST en Python
@jjmerelo
Por qué REST
REST significa representational state
transfer, y se ha convertido últimamente en la forma preferida
de programar servicios web por su versatilidad y aceptación en
todo tipo de lenguajes. Permite además estructurar fácilmente
una aplicación de forma que pueda ser usada por todo tipo de
front-ends, con todas las condiciones de seguridad que sean necesarias.
PUT
, GET
,
POST
y DELETE
Son las órdenes más usadas dentro de
los marcos REST, aunque hay otras. Cada una de ellas tiene
un significado específico, pero depende del programador que
se implemente ese significado
Diseñando un API REST
Hay buenas y malas formas de creat
un API REST . El API debe crearse alrededor de
colecciones y usar (y no repetir) los verbos de
HTTP
Publicando una clase
def uno(self,hito_id):
if hito_id > len(self.hitos['hitos']) or hito_id < 0:
raise IndexError("Índice fuera de rango")
return self.hitos['hitos'][hito_id]
El resto, en el enlace. Este es uno de
los que vamos a publicar
Usemos Hug
Hug es más rápido que Flask, documenta
automáticamente, es más fácil de usar y me ha aceptado pull
requests. Así que mola más que Flask-RESTful o cualquier
otro. Pyramid, por ejemplo, parece un poco más complicado
"""Hitos de IV servidos para usted"""
import hug
from HitosIV import HitosIV
estos_hitos = HitosIV()
@hug.get('/all')
def all():
"""Devuelve todos los hitos"""
return { "hitos": estos_hitos.todos_hitos() }
Una función bastante simple, que devuelve
todos los hitos, y lo hace en forma de JSON, que puede ser
interpretado fácilmente por cualquier cliente. La @ indica
que se trata de un decorador , es decir, un
envoltorio de una función. Como Python odia la programación
funcional, ha encontrado esta forma extraña de definir
encadenamiento de funciones.
Si no lo pruebas, está roto
Hablamos de tests unitarios ; tests que
se hacen sobre una sola función, sin hacer referencia a su
integración en el resto de una aplicación compleja
import hug
import hugitos
def test_should_have_correct_API():
data = hug.test.get(hugitos, '/all')
assert data.status == "200 OK"
assert data.data['hitos']['hitos'][0]['file'] == "0.Repositorio"
Usa simplemente assert
. Se
tendrá que testear con pytest
. En este caso,
usamos un sistema de test, hug.test
, que nos
evita tener que levantar el servidor y tirar de
él.
@hug.get('/one/{id}')
def one( id: int ):
"""Devuelve un hito"""
return { "hito": estos_hitos.uno( id ) }
En este caso necesitamos un
parámetro, y se lo pasamos directamente como parte del
URL. Si no se usa este método, se pasan como parámetros
con "?variable=valor". Viene a ser lo mismo.
>Si no se prueba...
def test_should_return_at_least_one_element():
data = hug.test.get(hugitos, '/one/0')
assert data.status == "200 OK"
assert data.data['hito']['file'] == "0.Repositorio"
Usamos directamente el nombre de la
clase importada y la variable estos_hitos
que hemos usado en el test anterior
Sirviendo
Publicando en la web
Heroku, OpenShift
También ciertos servicios dentro de la nube de Azure o Google, o zeit.co si se usa JavaScript
REST frameworks FTW
Usa siempre tests
Diseña con cuidado