Middleware

Middleware #

Middleware provides a convenient mechanism for inspecting and filtering HTTP requests entering your application. For example, gFly includes a middleware that verifies the user of your application is authenticated. If the user is not authenticated, the middleware will redirect the user to your application’s login screen. However, if the user is authenticated, the middleware will allow the request to proceed further into the application.

Additional middleware can be written to perform a variety of tasks besides authentication. For example, a logging middleware might log all incoming requests to your application. There are several middleware included in the gFly framework. All of these middleware are located in the app/http/middleware directory.

Middleware will affect child router groups and is not limited to levels.

Register Middleware #

There are two ways to add middleware to the router. Suppose there is a middleware registration in API router app/http/routes/api_routes.go as follows:

func ApiRoutes(f gfly.IFly) {
    // Write log all request URL
    f.Use(middleware.RequestMiddlewareFunc)

    f.Group("/api/v1", func(apiRouter *gfly.Group) {
        apiRouter.Group("/checking", func(groupChecking *gfly.Group) {
            // Check Authentication and Authorization 
            groupChecking.Use(middleware.ExtraMiddlewareFunc, 
				middleware.AuthMiddlewareFunc)

            groupChecking.GET("/unauthorized", api.NewDefaultApi())
            groupChecking.GET("/forbidden", api.NewDefaultApi())

            groupChecking.POST("/one", f.Middleware(middleware.RuleMiddlewareFunc)(api.NewDefaultApi()))
        })
    })
}

You can see that you can use 2 ways below to use Middleware:

  • Use Use() to apply routers at the same or nested level.
  • Use Middleware() to apply only to a specific Controller (Handler).

You can see there are 4 middleware functions: RequestMiddlewareFunc, ExtraMiddlewareFunc, AuthMiddlewareFunc and RuleMiddlewareFunc

Therefore, depending on the request, the amount of middleware that will be required to handle will be different:

  • All requests /* will be affected by at least a middleware RequestMiddlewareFunc.
  • Request URL /api/v1/checking/unauthorized and /api/v1/checking/forbidden will be affected by 3 middlewares RequestMiddlewareFunc, ExtraMiddlewareFunc, and AuthMiddlewareFunc.
  • Only request URL /api/v1/checking/one will be affected by 4 middleware RequestMiddlewareFunc, ExtraMiddlewareFunc, AuthMiddlewareFunc and RuleMiddlewareFunc.

Defining Middleware #

Middleware function must be a type of MiddlewareHandler

type MiddlewareHandler func(ctx *Ctx) error

Let review middleware RequestMiddlewareFunc. This middleware just print out URL requests

Create file request_middleware.go in folder app/http/middleware/

package middleware

import (
    "app/core/gfly"
    "app/core/log"
)

func RequestMiddlewareFunc(c *gfly.Ctx) error {
    log.Infof("Request %s", c.OriginalURL())

    return nil
}

Declare middleware into app/http/routes/web_routes.go or app/http/routes/api_routes.go

Below example add to web_routes.go

// WebRoutes func for describe a group of Web page routes.
func WebRoutes(f gfly.IFly) {
    // Write log all request URL
    f.Use(middleware.RequestMiddlewareFunc)

    // Web Routers
    ...
}

Browse http://localhost:7789/hello

and check log file storage/logs/logs.log and see more log content

2024/01/31 14:14:27.996562 request_middleware.go:9: [INFO] Request /hello

Simple task!. Therefore, this middleware does not need to check or block the processing flow of requests to the controller. So it will return nil. However, suppose you have middleware where necessity limits certain requests. Then you need to return error (any type) then the system will understand that the request is interrupted.