Cómo Plug.Router te ayuda a escribir microservicios en Elixir

Si no vas a aprovecharte de ni la mitad de las funciones que te aporta el framework Phoenix, que sepas que con Plug también puedes fabricar servicios o microservicios web utilizando el lenguaje de programación Elixir. Plug.Router es una estructura de datos que te va a facilitar la creación de estos servicios y declarar la lógica que quieres que se ejecute al visitar rutas.

Cuando queremos construir aplicaciones web en Elixir, Plug se presenta como una alternativa más ligera y directa frente a Phoenix. Mientras Phoenix nos ofrece un ecosistema muy completo con muchas funcionalidades listas para usar, Plug nos permite crear servidores compactos y específicos, ideales para microservicios que solo necesitan hacer un par de cosas concretas. Además, Plug es la base sobre la que se construye Phoenix, por lo que entenderlo nos ayuda a manejar casos más avanzados o personalizados dentro de aplicaciones Phoenix.

Para empezar a crear un router con Plug, lo primero es entender que este router será un módulo en el que definiremos funciones que se ejecutan según el método HTTP (GET, POST, PUT, DELETE, etc.) y la ruta que se visita. Esto nos permite activar comportamientos específicos simplemente accediendo a ciertas URLs.

Al crear un proyecto nuevo para nuestro microservicio, debemos añadir las dependencias necesarias. Plug por sí solo no incluye un servidor web, sino que funciona como una capa que se conecta a servidores externos. Por eso, es común usar Plug junto con Cowboy, un servidor web basado en Erlang, que es muy popular y está bien integrado con Phoenix. También existe Bandit, un servidor 100% Elixir que está ganando terreno, pero Cowboy sigue siendo la opción más estable y extendida actualmente.

Una vez configuradas las dependencias, podemos construir nuestro router creando un módulo que use Plug.Router. Este módulo nos proporciona macros para definir rutas y la lógica que queremos ejecutar cuando se accede a ellas. Es importante incluir al inicio las llamadas a plug :match y plug :dispatch, que son necesarias para que el router funcione correctamente y pueda procesar las rutas definidas.

Para definir una ruta, simplemente declaramos el verbo HTTP que queremos manejar, por ejemplo get, y le pasamos la ruta que queremos vigilar. Por ejemplo, para la raíz del sitio:

get "/" do
  IO.puts("Visita en la raíz")
  send_resp(conn, 200, "hola mundo")
end

Aquí, cuando alguien haga un GET a la raíz, se ejecutará el bloque que imprime un mensaje en consola y responde con un hola mundo. La variable conn representa la conexión web y es el objeto que Plug utiliza para manejar la petición y la respuesta.

Podemos definir tantas rutas como queramos, por ejemplo otra para /hola:

get "/hola" do
  IO.puts("Visita en la página hola")
  send_resp(conn, 200, "hola de nuevo")
end

Además, Plug permite manejar parámetros dinámicos en las rutas usando placeholders con dos puntos. Por ejemplo, para capturar cualquier valor después de /blog/ y usarlo como variable nombre:

get "/blog/:nombre" do
  send_resp(conn, 200, "Artículo para #{nombre}")
end

Así, si visitamos /blog/ventas o /blog/feliz-año, la variable nombre tendrá el valor correspondiente y podemos usarlo para personalizar la respuesta. Esto es muy útil para crear rutas dinámicas sin tener que definir cada una explícitamente.

Para poner en marcha nuestro router, debemos integrarlo con un servidor web. En nuestro caso, usamos Cowboy y lo hacemos creando una especificación de hijo para el árbol de supervisión con Plug.Cowboy.child_spec. Indicamos que queremos usar HTTP y le pasamos nuestro módulo router:

children = [
  Plug.Cowboy.child_spec(
    scheme: :http,
    plug: MicroservicioRouter.Router,
    options: [port: 4000]
  )
]

Supervisor.start_link(children, strategy: :one_for_one)

Luego, ejecutamos la aplicación con mix run --no-halt para que el servidor quede activo y podamos hacer peticiones. Por ejemplo, usando curl localhost:4000 recibiremos la respuesta hola mundo definida para la raíz.

Si probamos con otras rutas, como /hola, veremos la respuesta correspondiente, y si accedemos a /blog/algo, obtendremos el mensaje personalizado con el valor dinámico. Si visitamos una ruta no definida, como /blog sin nada más, obtendremos un error porque no hay un manejador para esa ruta exacta.

Además de GET, podemos definir rutas para otros métodos HTTP como POST o PUT, lo que nos permite construir APIs completas y manejar diferentes tipos de peticiones. También es posible crear varios routers y combinarlos usando forward, para modularizar el código y mantenerlo organizado, aunque eso queda para otro momento.

La función send_resp es fundamental para enviar respuestas HTTP y forma parte de la API de Plug.Conn, que ofrece muchas otras funciones para manipular la conexión: establecer cabeceras, manejar cookies, leer el cuerpo de la petición, entre otras. Esto nos da un control muy fino sobre cómo respondemos a cada solicitud.

Si estamos empezando con Plug, es recomendable familiarizarse con el objeto conn y su funcionamiento, ya que es la base para manejar las conexiones web en Elixir. Con esta base, podemos construir microservicios eficientes y modulares, integrándolos con otras herramientas como Ecto para persistencia, y aprovechar la ligereza de Plug frente a frameworks más pesados como Phoenix cuando no necesitamos toda su complejidad.

Lista de reproducción
  1. 1
    mix
    10 minutos
  2. 2
    Documentando código: comentarios, docs y moduledocs
    10 minutos
  3. 3
    Atributos de módulo
    9 minutos
  4. 4
    Dependencias
    12 minutos
  5. 5
    Un ejemplo práctico de módulo útil
    13 minutos
  6. 6
    Alias e import
    10 minutos
  7. 7
    Sobre las macros, require y use
    11 minutos
  8. 8
    Typespecs (parte 1, usando tipos básicos)
    10 minutos
  9. 9
    Typespecs (parte 2, tipos propios y t())
    11 minutos
  10. 10
    Comportamientos
    11 minutos
  11. 11
    Tratamiento de errores con rescue
    8 minutos
  12. 12
    Elevando errores con raise
    8 minutos
  13. 13
    with
    14 minutos
  14. 14
    Sigilos
    8 minutos
  15. 15
    Tests con ExUnit
    12 minutos
  16. 16
    Más particularidades de ExUnit
    13 minutos
  17. 17
    Microservicios en Elixir con Plug
    11 minutos
  18. 18
    Cómo Plug.Router te ayuda a escribir microservicios en Elixir
    14 minutos
  19. 19
    ¿Cómo hacer rutas dinámicas en Phoenix y Plug?
    13 minutos