Creando APIs con Flask

Hace unas semanas construimos dos componentes web para un cliente que buscaba una arquitectura de micro-servicios, una solución ideal para sistemas complejos.

Nuestro desarrollo desde enjambre representó sólo una parte del sistema completo, pero aún así esa parte cumple un rol importante y nos permitió mejorar nuestros skills a la hora de construir APIs y descubrimos algunas ideas nuevas, a tal punto que escribimos este post :)

¿Arquitectura de microservicios?

Es casi universal que todo desarrollo de sistemas comienza dividiendo la funcionalidad en partes más pequeñas. Ya sea que estemos hablando de sistemas web, aplicaciones nativas o simples scripts. Dividir un problema en partes más pequeñas es fundamental.

Lo que hace característica la idea de microservicios es que buscamos dividir el sistema en componentes independientes, generalmente como procesos que entienden HTTP e interactúan a través de la red.

Imaginá que esto trae varios beneficios potenciales: los servicios se pueden escribir en lenguajes diferentes, al ser independientes se pueden reemplazar individualmente, cambiar componentes no detiene la ejecución del sistema completo (¡todo sigue trabajando!) y el sistema completo puede escalar fácilmente, entre otras cosas.

Pero todo trae sus desafíos, en un sistema de microservicios aparecen otras necesidades: poder monitorizar el sistema completo, trabajar consistentemente en los mensajes, garantizar el funcionamiento y la integración de los componentes etc ...

El rol de las APIs

Ahora bien, como el funcionamiento del sistema necesita de la interacción e integración de los componentes, la comunicación y los protocolos se vuelven una pieza clave.

Diseñar una API consiste en describir los mensajes que entenderá, saber exactamente que información exponen, y cómo se integrará al resto de los servicios.

Así que al momento de desarrollar el sistema buscamos aplicar experiencia de otras personas, ideas como REST o incluso la especificación json-api. Pero dándole un enfoque particular, porque el sistema en el que participamos no tiene una sola fuente de datos, sino que la información está distribuida en varios dispositivos.

Una herramienta: Flask

Existen muchas formas de escribir APIs, y nosotros nos orientamos por Flask, una de nuestras tecnologías favoritas.

Flask es un micro-framework para desarrollar aplicaciones web y APIs, utilizando el lenguaje de programación python y un ecosistema desacoplado de componentes.

Lo característico de Flask, es que tiene un componente central (o núcleo) muy pequeño, y deja al programador tomar todas las decisiones de arquitectura por él mismo, Flask no incluye un ORM, adaptadores de base de datos o sistemas de login. Depende del programador tomar esas decisiones de diseño.

Así que para nosotros era la herramienta ideal, buscamos crear una API muy específica, y conocerla de principio a fin. ¡Que mejor que Flask para esto!.

Definiendo la estructura

Flask no viene con una estructura de aplicación predefinida, podemos implementar toda la API en un solo archivo .py o bien buscar una arquitectura propia.

En nuestro caso, tuvimos que implementar una arquitectura propia, basándonos en ideas propias de flask, pero adaptada para nuestro caso. Buscamos desde el principio lograr deploys rápidos, hacer testing de todas las rutas y tener una abstracción de datos independiente del motor de base de datos a utilizar.

Terminamos con una estructura de esta forma:

Y como quedamos muy contentos con el esquema, decidimos armar un repositorio con la estructura general (pero funcional) para reutilizar en futuros proyectos:

https://github.com/EnjambreBit/api-flask-sqlalchemy

Tests

Al implementar la API comenzamos escribiendo una batería de tests y una forma sencilla de ejecutarlos.

Esto fue super-productivo, porque pudimos poner en ejecución los tests y editar el código de la aplicación directamente, hasta cumplir con cada uno de los casos de uso.

Este es un ejemplo sencillo de algunos tests corriendo:

Interfaz web con Ember

La segunda herramienta que pusimos en práctica fue ember, ya que necesitábamos visualizar el estado del sistema e interactuar con la API de manera sencilla.

La interacción entre ember y un backend se suele hacer usando el patrón de diseño DataSource Adapter y ember-data, pero por suerte para nuestro caso eso se puede omitir, y hacer llamadas directas al backend.

Existe un método cada una de las rutas llamado "model", que ember espera invocar para conseguir los datos desde el backend.

En nuestro caso quedó tan sencillo como esto:

model() {  
  var url = API_HOST + "/users";
  return $.get(url);
}

Conclusiones

Combinar Flask y ember fue una buena idea, logramos avanzar relativamente rápido y sin inconvenientes gracias a los complementos y la estabilidad de las dos herramientas.

Naturalmente la flexibilidad de Flask nos jugó en contra a la hora de comenzar y tener que tomar muchas decisiones triviales de arquitectura, pero por suerte pudimos avanzar muy rápido, y con seguiridad, cuando completamos la estructura mínima, que mencioné antes. Que por cierto, ¡Se puede reutilizar!.