To the point - http middleware in go with net/http Part - 1
Tags: go, beginners, webdev, tutorial
Published: 2020-01-14 05:29:04


## What the hell middleware!
If you are programmer you have probably heard one of the two terms - "middleware" or "decorator"
They both achieve the same thing!

> A pattern that allows adding new behaviors to objects/functions dynamically by placing them inside special wrapper objects/functions. This allows wrapping countless number of times since both input and output follow the same interface.



## Requirement:
Create two middlewares:
1. logMw: for logging req and response
2. loggedInMw: for verifying that a user is logged in

Create one handler:
1. "/me" shows basic user information if not logged in. But shows more info if user is logged in

## Thinking:
I should be able to use the middleware like this:
```go
mux.HandleFunc("/", logMw(loggedInMw(userInfo)))
```
where userInfo is my http.HandlerFunc
and lowMw and loggedInMw are the middlewares

## More thinking:
A middleware then is a function that accepts and returns a HandlerFunc, thus enabling chaining
```go
func(next http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        //middleware logic
        .... // can operate on w and r
        
        //call next in the end
        next(w, r)
    }
}
```

## Code it!

From now on see my comments inline.
> Note: The pattern to add a <span style="color:red"> header called "loggedIn" is not the right thing to do </span>. We will look at how to make it right, but for this example bear with me.

```go
package main

import (
    "fmt"
    "log"
    "math/rand"
    "net/http"
    "time"
)

var mux *http.ServeMux = http.NewServeMux()

func main() {
    mux.HandleFunc("/", lowMw(loggedInMw(userInfo)))
    fmt.Println("server running on 8080")
    log.Fatal(http.ListenAndServe(":8080", mux))

}

// check header "loggedIn"
func userInfo(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte(w.Header().Get("loggedIn")))
}

// log the req and response after the final handler has been called
func lowMw(next http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        // start middleware logic
        t := time.Now()
        next(w, r)
        fmt.Printf(`[%v] {"r.Method": "%s", "r.URL.Path": "%s", "status": "%v", "timeTakenµs":"%v", "loggedIn": "%s"}
`, t.UTC(), r.Method, r.URL.Path, 200, time.Since(t).Nanoseconds(), w.Header().Get("loggedIn"))
    }
}

// check if user is logged or not and set a header called "loggedIn" for next handlerFunc to read from
func loggedInMw(next http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        // start middleware logic
        //
        // dummy process of setting loggedIn = true
        rand.Seed(time.Now().UnixNano())
        temp := rand.Intn(2)
        var loggedIn string = "no"
        if temp == 0 {
            loggedIn = "yes"
        } 
        // end of dummy process
        //
        w.Header().Set("loggedIn", loggedIn)
        // end of middleware logic
        next(w, r)
    }
}

```

#### Output 

Checkout the "loggedIn" in the log below! We did!

```
[2020-01-14 03:50:39.7792098 +0000 UTC] {"r.Method": "GET", "r.URL.Path": "/", "status": "200", "timeTakenµs":"0", "loggedIn": "yes"}
[2020-01-14 03:50:39.9446553 +0000 UTC] {"r.Method": "GET", "r.URL.Path": "/", "status": "200", "timeTakenµs":"0", "loggedIn": "no"}
[2020-01-14 03:50:40.1101016 +0000 UTC] {"r.Method": "GET", "r.URL.Path": "/", "status": "200", "timeTakenµs":"0", "loggedIn": "yes"}
[2020-01-14 03:50:40.2615089 +0000 UTC] {"r.Method": "GET", "r.URL.Path": "/", "status": "200", "timeTakenµs":"0", "loggedIn": "yes"}
[2020-01-14 03:50:40.4339753 +0000 UTC] {"r.Method": "GET", "r.URL.Path": "/", "status": "200", "timeTakenµs":"0", "loggedIn": "yes"}
[2020-01-14 03:50:40.5863852 +0000 UTC] {"r.Method": "GET", "r.URL.Path": "/", "status": "200", "timeTakenµs":"0", "loggedIn": "yes"}
```

### You may like to read the series:
```
# To the point - http middleware in go with net/http Part - 1
# To the point - http middleware in go with net/http Part - 2
```