Middleware

    Overview

    Middleware can be used for modifying or filtering incoming requests. For example, a middleware could be added that checks the user session and returns an Unauthorized response if the user is not logged in.

    Middleware is expressed as a function that accepts Request, Response, and Next arguments. Think of middleware as a link in a chain. Each middleware is executed in the order that it’s added and each can choose whether to continue to the next link or break the chain and return a response.

    The Use and With methods can be used to add middleware to the router.

    r.Use(func(req h.Request, res h.Response, next h.Next) h.Result {
    	fmt.Println("Hello from middleware!")
    	return next(req, res)
    })
    
    // Add multiple middleware at once
    router.Use(middleware1, middleware2, middleware3)
    
    // Create a new router instance with middleware
    adminRouter := router.With(adminOnlyMiddleware)
    adminRouter.Get("/admin", adminRoute)
    

    Examples

    Middleware is best explained by example so here are a few to get you started. The first example defines a middleware to print the URL of every incoming request.

    // Middleware to log all request URLs
    r.Use(func(req h.Request, res h.Response, next h.Next) h.Result {
    	fmt.Printf("URL: %s\n", req.URL())
    	return next(req, res)
    })
    

    Middleware can also prevent further execution and return an early response. Here is a basic middleware that prevents access to all URLs starting with /admin/*.

    // Middleware to prevent access to /admin/ routes
    r.Use(func(req h.Request, res h.Response, next h.Next) h.Result {
    	if strings.HasPrefix(req.URL().Path, "/admin/") {
    	    return res.Status(401).Data("Not Allowed!")
        }
        return next(req, res)
    })
    

    And finally, here is an example of a middleware that adds CORS headers to every response.

    // Middleware to set default headers
    r.Use(func(req h.Request, res h.Response, next h.Next) h.Result {
    	res.Header("Access-Control-Allow-Origin", "*")
        res.Header("Access-Control-Allow-Methods", "GET, POST")
        return next(req, res)
    })
    

    Go Middleware

    Since Hemlock-style middleware uses a different interface than most Go programs, native Go middleware is also supported using the UseG and WithG methods.

    This allows the use of popular middleware libraries like github.com/gorilla/handlers without having to rewrite third-party code.

    import "github.com/gorilla/handlers"
    
    func setupRoutes (r h.Router) {
        r.UseG(handlers.RecoveryHandler())
        r.UseG(handlers.CompressHandler)
        r.Use(myHemlockMiddleware)
        // ...
    }