Cómo construir un middleware efectivo
Partes constituyentes
Normalmente, un middleware consta de dos partes:
-
La primera parte se ejecuta una vez, cuando inicializas tu middleware. Aquí es donde configuras objetos globales, lógica de configuración, etc.; todo lo que solo necesita suceder una vez en el ciclo de vida de la aplicación.
-
La segunda parte se ejecuta en cada petición. Por ejemplo, en un middleware de base de datos, inyectarías tu objeto global de base de datos en el contexto de la solicitud. Una vez en el contexto, otros middlewares y tus funciones controlador pueden recuperarlo y utilizarlo.
func funcName(params string) gin.HandlerFunc { // <--- // Esta es la primera parte // ---> // Ejemplo de inicialización: validar parámetros de entrada if err := check(params); err != nil { panic(err) }
return func(c *gin.Context) { // <--- // Esta es la segunda parte // ---> // Ejecución por solicitud: inyectar en el contexto c.Set("TestVar", params) c.Next() }}
Proceso de ejecución
Veamos el siguiente ejemplo de código:
func main() { router := gin.Default()
router.Use(globalMiddleware())
router.GET("/rest/n/api/*some", mid1(), mid2(), handler)
router.Run()}
func globalMiddleware() gin.HandlerFunc { fmt.Println("globalMiddleware...1")
return func(c *gin.Context) { fmt.Println("globalMiddleware...2") c.Next() fmt.Println("globalMiddleware...3") }}
func handler(c *gin.Context) { fmt.Println("exec handler.")}
func mid1() gin.HandlerFunc { fmt.Println("mid1...1")
return func(c *gin.Context) {
fmt.Println("mid1...2") c.Next() fmt.Println("mid1...3") }}
func mid2() gin.HandlerFunc { fmt.Println("mid2...1")
return func(c *gin.Context) { fmt.Println("mid2...2") c.Next() fmt.Println("mid2...3") }}
Según la sección Partes constituyentes anterior, cuando ejecutas el proceso Gin, la primera parte de cada middleware se ejecuta primero e imprime la siguiente información:
globalMiddleware...1mid1...1mid2...1
El orden de inicialización es:
globalMiddleware...1 | vmid1...1 | vmid2...1
Cuando realizas una solicitud—por ejemplo, curl -v localhost:8080/rest/n/api/some
—la segunda parte de cada middleware se ejecuta en orden y muestra lo siguiente:
globalMiddleware...2mid1...2mid2...2exec handler.mid2...3mid1...3globalMiddleware...3
En otras palabras, el orden de ejecución es:
globalMiddleware...2 | vmid1...2 | vmid2...2 | vexec handler. | vmid2...3 | vmid1...3 | vglobalMiddleware...3