Cómo construir un middleware efectivo
Partes constituyentes
Un middleware generalmente consta de dos partes:
-
La primera parte se ejecuta una sola vez, cuando inicializas tu middleware. Aquí es donde configuras objetos globales, lógica de configuración, etc., todo lo que solo necesita ocurrir una vez durante el tiempo de vida de la aplicación.
-
La segunda parte se ejecuta en cada solicitud. Por ejemplo, en un middleware de base de datos, inyectarías tu objeto de base de datos global en el contexto de la solicitud. Una vez que está en el contexto, otros middlewares y tus funciones handler pueden recuperarlo y usarlo.
func funcName(params string) gin.HandlerFunc { // <--- // This is part one // ---> // Example initialization: validate input params if err := check(params); err != nil { panic(err) }
return func(c *gin.Context) { // <--- // This is part two // ---> // Example execution per request: inject into context c.Set("TestVar", params) c.Next() }}Proceso de ejecución
Veamos el siguiente código de ejemplo:
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...1El orden de inicialización es:
globalMiddleware...1 | vmid1...1 | vmid2...1Cuando haces una solicitud, por ejemplo, curl -v localhost:8080/rest/n/api/some, la segunda parte de cada middleware se ejecuta en orden y produce la siguiente salida:
globalMiddleware...2mid1...2mid2...2exec handler.mid2...3mid1...3globalMiddleware...3En otras palabras, el orden de ejecución es:
globalMiddleware...2 | vmid1...2 | vmid2...2 | vexec handler. | vmid2...3 | vmid1...3 | vglobalMiddleware...3