middleware provide a mechanism for filtering or inspecting http requests entering to your application, example you need to verify user authentication or authorization before access something request to your http, middleware running before and and after request happened.
Today we can try the middleware with package http/net.
Step 1 - Create simple http server
touch main.go
...next open main.go
with your code editor.
package main
import (
"http/net"
"io"
)
func main() {
r := http.NewServeMux()
r.HandleFunc("/", func(rw http.ResponseWriter, r *http.Request) {
io.WriteString(rw, `{"message": "hello world.."}`)
})
http.ListenAndServe(":8000", r)
}
...execute main.go
with go run
go run main.go
...open another terminal then run curl http://localhost:8000
curl http://localhost:8000
{"message": "hello world.."}
Step 2 - Add middleware
Open main.go
then write function middleware.
func TheLogger(next http.Handler) http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
fmt.Println(fmt.Sprintf("%s %s", r.Method, r.URL.Path))
next.ServeHTTP(rw, r)
})
}
Interface http.Handler
is a handler response to an HTTP request. http.Handler
have return ServeHTTP
to reply headers and data to the ResponseWriter.
I name middleware with TheLogger
to get response method, and url path.
Next, in main function we just wrap the router with TheLogger
middleware, cause http.NewServeMux
also implement interface http.Router
, and for more please check in next steps.
Step 3 - Use TheLogger
in http server.
package main
import (
"fmt"
"io"
"net/http"
)
func TheLogger(next http.Handler) http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
fmt.Println(fmt.Sprintf("%s %s", r.Method, r.URL.Path))
next.ServeHTTP(rw, r)
})
}
func main() {
r := http.NewServeMux()
r.HandleFunc("/", func(rw http.ResponseWriter, r *http.Request) {
io.WriteString(rw, `{"message": "hello world.."}`)
})
m := TheLogger(r)
http.ListenAndServe(":8000", m)
}
...save and run with go run main.go
curl http://localhost:8000
❯ go run main.go
GET / --> log from middleware
Ok, next we need to add context in middleware.
Step - 4 Add context in middleware
// create context
ctx := context.WithValue(r.Context(), "data", "data:test")
Please learn more about the context in here
Step - 5 Add http.Request
context to TheLogger
middleware.
func TheLogger(next http.Handler) http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
fmt.Println(fmt.Sprintf("%s %s", r.Method, r.URL.Path))
// create context
ctx := context.WithValue(r.Context(), "data", "data:test")
// inject the context in http.Request with r.WithContext
next.ServeHTTP(rw, r.WithContext(ctx))
})
}
Step - 6 Get context data.
getContextData := r.Context().Value("data")
r http.Request
get context with r.Context().Value(<context_key>)
...
func main() {
r := http.NewServeMux()
r.HandleFunc("/", func(rw http.ResponseWriter, r *http.Request) {
// get context data
getContextData := r.Context().Value("data")
fmt.Println(getContextData)
io.WriteString(rw, `{"message": "hello world.."}`)
})
m := TheLogger(r)
http.ListenAndServe(":8000", m)
}
❯ go run main.go
GET / -> log from middleware
data:test -> context from middleware
...full code
package main
import (
"context"
"fmt"
"io"
"net/http"
)
func TheLogger(next http.Handler) http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
// print log r.Method and r.URL.Path
fmt.Println(fmt.Sprintf("%s %s", r.Method, r.URL.Path))
// create context
ctx := context.WithValue(r.Context(), "data", "data:test")
// inject the context in http.Request with r.WithContext
next.ServeHTTP(rw, r.WithContext(ctx))
})
}
func main() {
r := http.NewServeMux()
r.HandleFunc("/", func(rw http.ResponseWriter, r *http.Request) {
// get context data
getContextData := r.Context().Value("data")
fmt.Println(getContextData)
io.WriteString(rw, `{"message": "hello world.."}`)
})
m := TheLogger(r)
http.ListenAndServe(":8000", m)
}
Final, In real case you can using middleware to validate authorization user and etc, and request with context for sharing data via http.Request
.
Reference:
Top comments (0)