+++ draft = false date = 2021-08-01T22:05:04+05:00 title = "Writing a Middleware for your HTTP handler – Golang" description = "" slug = "" authors = ["Basit Ali"] tags = ["golang", "middleware", "http", "handler"] categories = [] externalLink = "" series = [] +++ If you are a backend developer working daily with HTTP requests then you have most likely already encountered situations where you want a common functionality across all the incoming HTTP requests, which can be as simple as checking if the `Content-Type` header only has the value `application/json` if you only support json, or maybe you want to spoof your HTTP request to change the method type from `POST`,`GET` or `PUT` to something else based on the `X-HTTP-Method-Override` header, or of course authenticate before finally passing the request to the destination HTTP handler. You can achieve the following behaviour by writing a `middleware`, also known as a `filter` in some other backend frameworks. You can have as many middlewares as you want, each with a separate responsibility, and can chain them together to funnel incoming HTTP requests. Writing a `middleware` in Go is pretty simple, you just need to **wrap** your `middleware` around the base HTTP handler, which so to speak is a thin **wrapper** around your HTTP handler. Lets start with `http` package's `ListenAndServe` method, which listens for incoming connections and serves with the handler to handle the requests, and lets write a handler for root `"/"` path which checks for the header `Content-Type` to see if it's `application/json`, because our API only accepts JSON, and respond with following json `{"msg":"Hello world!"}` to any incoming request: ```go func main() { mux := http.NewServeMux() mux.HandleFunc("/", rootHandler) http.ListenAndServe(":8080", mux) } func rootHandler(w http.ResponseWriter, r *http.Request) { if r.Header.Get("Content-Type") != "application/json" { http.Error(w, "Only application/json content type supported", http.StatusUnsupportedMediaType) return } w.Write([]byte(`{"msg":"Hello world!"}`)) } ``` Of course in reality you could have a dozen of handlers each with a different endpoint, but lets keep it simple for this tutorial. Now let's assume we have a dozen request handlers in our project and we want each handler to check for `Content-Type` header as we did in our `rootHandler`, we want our code to be DRY *(Don't Repeat Yourself)*. Which brings us to writing a `middleware` to check the `Content-Type` header for each incoming request. Lets write a middleware and call it `wrap`: ```go func wrap(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // middleware logic next.ServeHTTP(w, r) }) } ``` The `wrap` function takes in a `Handler` and returns a `Handler`, this syntax allows it to be used where we would normally use a request handler, and also allow us to chain multiple middlewares together. Now we can do something like `wrap(handler)` instead of just using `handler`, this would call our `middleware` logic before calling `next.ServeHTTP(w, r)` which can be the next middleware in the chain or a final call to our request handler. In the following example, we are wrapping our `wrap` middleware around `mux` so every incoming request will pass through our middleware first: ```go func main() { mux := http.NewServeMux() mux.HandleFunc("/", rootHandler) http.ListenAndServe(":8080", wrap(mux)) } func rootHandler(w http.ResponseWriter, r *http.Request) { w.Write([]byte(`{"msg":"Hello world!"}`)) } func wrap(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.Header.Get("Content-Type") != "application/json" { http.Error(w, "Only application/json content type supported", http.StatusUnsupportedMediaType) return } next.ServeHTTP(w, r) }) } ``` So far we've been using a single middleware, lets see multiple middlewares chained together in action. We can define multiple middlewares with the same signature as of `wrap`, replacing the comment `// middleware logic` with our code. >```go > func wrap(next http.Handler) http.Handler { > return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { > // middleware logic > next.ServeHTTP(w, r) > }) > } >``` Lets rename `wrap` to `enforceJSON`, and write another `middleware` which will log every incoming request's method and path, and chain them both together: ```go func main() { mux := http.NewServeMux() mux.HandleFunc("/", rootHandler) http.ListenAndServe(":8080", logRequest(enforceJSON(mux))) } func rootHandler(w ResponseWriter, r *Request) { w.Write([]byte(`{"msg":"Hello world!"}`)) } func logRequest(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Println(r.Method, r.URL.Path) // logs: GET /v1/users/1234 next.ServeHTTP(w, r) }) } func enforceJSON(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.Header.Get("Content-Type") != "application/json" { http.Error(w, "Only application/json content type supported", http.StatusUnsupportedMediaType) return } next.ServeHTTP(w, r) }) } ``` See how we are using `logRequest(enforceJSON(mux))` instead of `wrap(mux)`? Now every incoming HTTP request will be logged and then checked for `Content-Type` before being passed onto the handler. A cleaner way to chain multiple handlers is writing a single `wrap` middleware and chain all the middlewares inside `wrap`: ```go func wrap(handler http.Handler) http.Handler { handler = enforceJSON(handler) handler = logRequest(handler) return handler } ``` And then instead of: ```go http.ListenAndServe(":8080", logRequest(enforceJSON(mux))) ``` We can use: ```go http.ListenAndServe(":8080", wrap(mux)) ``` ----------- That's all on middlewares in golang today. Hope it was useful with your understanding on middlewares or how to write them.