Enrutador y Middleware en Go con Gorilla Mux

En un post anterior vimos cómo responder peticiones HTTP con rutas en Go, pero las mismas no eran tan simples cuando se trataba de variables en la URL o métodos HTTP.

Hoy vamos a ver un enrutador o router de Go, que permite definir rutas y métodos HTTP para responder a ellos, de una manera fácil.

El enrutador, llamado Mux (que es de las herramientas de Gorilla) permite:

  • Definir middleware en las rutas, es decir, aplicar funciones que se ejecutan antes de cada petición HTTP y que permiten detener la ejecución o loguear determinadas cosas
  • Definición de rutas con verbos HTTP
  • Lectura de parámetros GET
  • Lectura de variables dentro de la url. Por ejemplo si definimos algo como usuario/{id} y se consulta a usuario/1 podemos obtener el valor 1 accediendo a la variable
  • Variables dentro de la URL con expresiones regulares

En resumen, Mux es un router de Go que soporta además Middleware. Veamos algunos ejemplos del mismo.

Si quieres ver el código final míralo en GitHub.

Nota: si usas PHP te recomendo Phroute.

Instalar Go y Gorilla mux

Comienza instalando Go en Windows o Linux, después de eso instala la librería con:

go get github.com/gorilla/mux

Crear y definir una ruta

Hay que importar la librería y después crear el enrutador:

Eso solo crea el enrutador. Para agregarle handlers o manejadores de rutas invocamos a la función HandleFunc que recibe dos argumentos:

  1. La URL a la que responderá
  2. Una función que va a manejar la petición. Dicha función es un handler de HTTP y tiene como argumentos la petición y la respuesta HTTP.

Veamos un ejemplo:

Cuando se visite la url /hola se llamará a esa función. Dentro de esa función podemos invocar a más código que consulte datos o haga algo y después escriba la respuesta HTTP.

Se puede decir que este es nuestro pegamento o controlador si conocemos MVC.

No es necesario indicar el método, pero lo pongo para que se vea cómo se puede indicar a qué método HTTP responderá la petición (GET)

También se pueden crear middlewares, pero eso lo veremos más adelante.

El servidor HTTP combinado con el enrutador

El enrutador solo mapea las URL de las peticiones, pero debemos iniciar un servidor para que las mismas sean servidas.

En Go es muy fácil definir un servidor. Lo configuramos para que el handler sea el enrutador que acabamos de crear, y llamamos al método ListenAndServe()

Definir el handler de manera separada

No es necesario complicar el código de esa manera (personalmente lo veo limpio pero alguien puede diferir), ya que podemos definir antes el handler y después pasarlo como argumento, teniendo un código más limpio:

En la primera línea definimos la ruta, pero definimos la función manejadora de manera aparte. No te compliques por la función, lo único que hace es devolver un JSON de usuarios.

Variables en la URL

Mux permite leer las variables dentro de la URL de manera sencilla a través del método mux.Vars() que recibe la petición y devuelve un mapa de la variables.

Veamos un ejemplo en donde se consultan las ventas de determinado tipo y año:

Es tan fácil como acceder al mapa de variables. Todas las variables son recibidas como cadenas, pero se pueden convertir a entero con distintos métodos dependiendo del tipo de dato.

En el siguiente ejemplo se convierte una cadena a entero, la cadena es el id de un usuario que se quiere recuperar:

Variables en la URL con expresión regular

Ahora veamos cómo atrapar las variables pero solo si cumplen una expresión regular. Para ello definimos la expresión después de nombrar la variable, separando ambas partes con dos puntos:

La expresión regular indica que solo tomará en cuenta lo que sea formado con dígitos del 0 al 9 y que tenga 4 cifras. Lo sé, no funcionará para el año 10000 pero para los años actuales funciona y solo es un ejemplo.

También podemos tener opciones fijas:

Podemos separar las opciones con el pipe |. Es importante poner el ?: para que no sea un grupo de captura y se confunda al hacer expresiones regulares.

Parámetros GET

Los parámetros GET de una ruta son aquellos que van separados por un ampersand y un signo de interrogación al inicio. Por ejemplo:

http://localhost:8000/cursos?orden=ascendente&orden=descendente&busqueda_titulo=atlas&busqueda_autor=ayn

Para manejarlos debemos acceder a los valores según la documentación de Go, pues Mux no tiene nada que ver con esto.

La ventaja es que podemos usar los valores GET y las rutas al mismo tiempo. Así:

Se accede a los valores a través de peticion.URL.Query; eso devolverá un mapa de arreglos. Para acceder al valor hay que comprobar la longitud del arreglo, ya que si el valor no está presente el arreglo medirá cero.

Más métodos: PUT, POST, DELETE

Hasta ahora todos los métodos que hemos visto son GET. Veamos cómo manejar una petición POST, la cual trae un cuerpo:

El primer cambio importante es que ahora llamamos a Method con POST.

El segundo es que definimos un struct para leer un JSON. Ese JSON debe ser enviado cuando se solicite la ruta, y debe coincidir con el struct.

Si la lectura es exitosa podemos trabajar con esa variable, guardarla o hacer algo con ella.

Los métodos más comunes quedan definidos así:

Al final del post dejaré un ejemplo completo, no te preocupes si no defino las funciones por ahora.

Middleware con Gorilla Mux

Un Middleware es algo que permite que todas las peticiones pasen por un lugar antes de ser servidas.

El Middleware puede decidir atender la petición o rechazarla, o simplemente agregarle datos y dejar que el siguiente método se encargue.

Es decir, el Middleware es algo que está en medio. Como ejemplo básico tenemos un middleware que loguea cada petición. Queda así:

Es una función simple que devuelve un http.HandlerFunc, las mismas funciones que hemos estado viendo. Lo interesante está en el parámetro que recibe: un http.Handler.

Middleware en Go

Como es un middleware de log no vamos a detener o continuar la petición, así que invocamos el siguiente manejador con siguienteManejador.ServeHTTP pasándole la respuesta y la petición.

Es de gran importancia mencionar que si no se llama al siguiente manejador, la petición se detiene ahí mismo o mejor dicho se cancela.

Con eso definimos el middleware, pero no lo estamos usando. Para usarlo debemos invocar el método Use de nuestro enrutador.

enrutador.Use(middlewareLog)

Podemos definir muchos middlewares y serán llamados en el orden en el que llamemos a Use.

Veamos otro ejemplo de Middleware que ahora sí detiene o deja continuar la ejecución de la petición:

El funcionamiento de este middleware es muy simple: si el método de la petición es DELETE entonces genera un error y detiene la ejecución de la petición.

Si el método no es DELETE entonces llama al siguiente handler. Lo hice así de simple para demostrar cómo se usa, pero podemos comparar otras cosas, obtener sesiones, encabezados, llamar a bases de datos, etcétera.

Encerrar la definición de rutas en otro archivo

Es una buena práctica definir nuestras rutas  y middlewares en un archivo distinto a donde creamos el servidor, así lo tenemos separado y el mantenimiento es más rápido.

Mi archivo de rutas completo queda como se ve a continuación. Para probar estoy trabajando con arreglos fijos, pero solo son ejemplos, no te preocupes mucho por el funcionamiento interno, sino por las rutas.

Poniendo todo junto y compilando

El archivo main.go queda así:

Recuerda que las rutas quedaron arriba. Ahora se compila con:

go build

Y se ejecuta el archivo resultante. Al visitar localhost las rutas funcionan como en las imágenes mostradas.

Conclusión

Dejo la documentación oficial y el enlace al repositorio en donde está todo el código.

Encantado de ayudarte


Estoy disponible para trabajar en tu proyecto, modificar el programa del post o realizar tu tarea pendiente, no dudes en ponerte en contacto conmigo.

No te pierdas ninguno de mis posts

Suscríbete a mi canal de Telegram para recibir una notificación cuando escriba un nuevo tutorial de programación.

Dejar un comentario