Cómo implementar microservicios con Python en minutos

Las arquitecturas software orientadas a microservicios se están convirtiendo en un standard para la construcción de aplicaciones modernas desplegadas continuamente en plataformas Cloud. Martin Fowler, uno de los firmantes del Manifiesto Ágil y una de las personas más influyentes en el mundo del software, profundizó en el concepto de arquitecturas orientadas a microservicios en este artículo de obligada lectura.

Sin duda este nuevo estilo de arquitectura se está imponiendo en entornos donde las necesidades de escalabilidad son muy fuertes y el diseño en componentes independientes es una gran ventaja a la hora de abordar problemas complejos. En Paradigma hemos escrito varios artículos profundizando en diferentes aspectos a tener en cuenta a la hora de enfrentarse a arquitecturas orientadas a microservicios como la orquestación, la monitorización o el despliegue.

En este artículo, sin embargo, queremos profundizar en una de las grandes ventajas de los microservicios: el poliglotismo.

microservicios-python

¿Por qué desarrollar microservicios en Python?

Uno de los principios de este estilo de arquitectura es que los servicios deben de tender a ser lo más cohesionados posibles, minimizando al máximo el acoplamiento entre ellos. La comunicación entre los servicios se ha de implementar a través de mecanismos ligeros, preferiblemente APIs basados en HTTP, como por ejemplo APIs RESTful/JSON.

Estos sistemas de comunicación agnósticos nos abren la puerta a que podamos desarrollar cada microservicio con el lenguaje y las herramientas que más nos convenga en cada caso. Por ejemplo, si en un microservicio en concreto el rendimiento es un aspecto crítico, podemos escoger lenguajes de bajo nivel que nos permitan afinar más este aspecto como C, C++ o Go. Sin embargo en otros casos nos interesará escoger lenguajes de alto o nivel o que implementen ciertas características particulares, como Python, Ruby, Groovy o Scala, que nos permitan avanzar más rápido o se acomoden mejor al servicio que deben implementar.

Llegados a este punto debemos plantearnos qué opciones o plataformas pueden ser interesantes a la hora de implementar estos servicios que exponen APIs REST más allá de los lenguajes que nos ofrece la JVM y de los frameworks habituales en el ecosistema Java, en ocasiones demasiado pesados.

python-logo

Sin duda una de las mejores opciones a tener en cuenta es usar un lenguaje de alto nivel como Python, del que podemos aprovechar muchas de sus ventajas ya que es un lenguaje interpretado y de tipado dinámico. Python es ampliamente utilizado, por lo que tiene una gran base de programadores. Combina múltiples paradigmas de programación como el orientado a objetos y el funcional. Además, su sintaxis está orientada escribir menos líneas de código pero más claras que otros lenguajes, lo que facilita enormemente su mantenimiento.

Por otro lado, existen excelentes frameworks y bibliotecas muy asentados y orientados al desarrollo de APIs REST y sistemas de comunicación basados en HTTP, lo que es perfecto para la construcción de microservicios. Algunos de los frameworks más interesantes para construir APIs REST son:

django-rest

Ejemplo

Vamos a ver un ejemplo de cómo construir en pocas líneas un pequeño microservicio que exponga un API REST para manejar “customers” con Django y REST Framework.

En este caso vamos a tener que definir los siguientes elementos, cada uno en un fichero Python:

  • Modelo: Aquí definiremos las propiedades y métodos de nuestro modelo de clientes.
  • Vista: En este apartado implementaremos la funcionalidad que queremos ofrecer asociada en este microservicio en torno al recurso “Customer”.
  • Router: En este punto asociaremos la lógica definida en el punto anterior en rutas y métodos HTTP concretos.
  • Serializador: Es necesario definir el formato y estructura de los datos que recibe y devuelve nuestro API.
  • Test: Aquí podemos definir un conjunto de tests que validen nuestra API.

 

models.py

En este fichero vamos a definir cómo será nuestro modelo “Customer”, esto lo hacemos a través de la definición de una clase que herede de “Model”. Esta clase incluirá una serie de propiedades y sus tipos de datos que serán los atributos que tendrá un cliente. El ORM de Django convertirá esta información en una tabla en la base de datos que elijamos.

from django.db.models import Model, UUIDField, CharField, EmailField, DateTimeField

class Customer(Model):
    id = UUIDField(primary_key=True)
    name = CharField(max_length=45)
    surname = CharField(max_length=45)
    phone = CharField(max_length=45)
    email = EmailField()

 

views.py

from rest_framework import viewsets

from customer.models import Customer
from customer.serializers import CustomerSerializer

class CustomerViewSet(viewsets.ModelViewSet):
    model = Customer
    queryset = Customer.objects.all()
    serializer_class = CustomerSerializer

En la vista le indicamos a Django que queremos basarnos en el modelo “Customer”, que hemos definido para construir un API asociada a este modelo. Al heredar de “ModelViewSet” el API que expondremos será CRUD y ofrecerá los siguientes métodos:

  • POST /api/customers/
  • GET /api/customers/
  • PUT /api/customers/{pk}/
  • DELETE /api/customers/{pk}/
  • GET /api/customers/{pk}/
  • PATCH /api/customers/{pk}/

Además le indicamos que para la representación del recurso “Customer” debe de usar la clase “CustomerSerializer”.

urls.py

from rest_framework.routers import DefaultRouter

from customer.views import CustomerViewSet

router = DefaultRouter()
router.register('customers', CustomerViewSet, 'Customer')
urlpatterns = router.urls

En el fichero de URLs se define el punto desde el cual colgará el API de customer, en este caso será en /customers/ y desde aquí colgarán el resto de URLs asociadas a este recurso.

serializers.py

from rest_framework import serializers

from customer.models import Customer

class CustomerSerializer(serializers.ModelSerializer):
    class Meta:
        model = Customer

Los serializadores nos permiten implementar cambios en la representación y serialización de los recursos, limitar la información que devolverá el API y con qué estructura. En este caso dejamos que el framework infiera del modelo los campos y los renderice todos de acuerdo a su tipo de datos. Esta sería la opción predeterminada.

tests.py

from django.core.urlresolvers import reverse

from rest_framework import status
from rest_framework.test import APITestCase

from customer.models import Customer

class AccountTests(APITestCase):
    def test_create_customer(self):
        url = reverse('customer-list')
        data = {
            'id': '550e8400-e29b-41d4-a716-446655440000',
            'name': 'John',
            'surname': 'Smith',
            'email': 'jsmith@test.com',
            'phone': '609148275'
        }
        response = self.client.post(url, data, format='json')

        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertEqual(Customer.objects.count(), 1)
        self.assertEqual(Customer.objects.get().name, 'John')

Por último definiremos un juego de tests que pruebe nuestra API. En este caso, a modo de ejemplo, definiremos un único test que envíe una petición POST con un body de ejemplo y haga las siguientes comprobaciones:

  • Que el código HTTP devuelto sea 201.
  • Que se haya insertado un objeto customer en la base de datos.
  • Que el nombre de este objeto sea “John” que era el nombre que habíamos incluido en el body de la petición POST.

Documentación del API

Podemos navegar por el API que acabamos de generar usando la herramienta que nos viene incluida con Django Rest Framework.

django-rest-framework

También podemos activar fácilmente otros sistemas de documentación de APIs como Swagger que se integran perfectamente con Django a través del paquete django-rest-swagger.

swagger

Conclusión

El estilo de arquitectura orientado a microservicios nos permite integrar diferentes lenguajes y frameworks, de esta forma podemos aprovechar lo mejor de cada uno. Python es un lenguaje moderno y muy potente para el desarrollo rápido de microservicios. Además, combinado con los frameworks y herramientas del ecosistema Python, lo convierten, sin duda, en una alternativa muy interesante.

Manuel Zaforas es Ingeniero Superior en Informática por la UPM. Está interesado en HPC, IoT, Cloud, NoSQL, Big Data, Data Science, Machine Learning y Agile. Apoya activamente la implantación de software libre, la calidad en los procesos de desarrollo de software a través de la mejora continua y la innovación en las metodologías de desarrollo y gestión de equipos. Actualmente trabaja en Paradigma como Scrum Master y Arquitecto Software.

Ver toda la actividad de Manuel Zaforas

Recibe más artículos como este

Recibirás un email por cada nuevo artículo.. Acepto los términos legales

Posts relacionados

Escribe un comentario