+++ 
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.