Middleware
Dalam pembuatan web, konsep middleware sering kita dengar atau filter atau interceptor yang mana ini adalah sebuah fitur yang kita bisa menambahkan kode sebelum dan setelah sebuah handler dieksekusi.
sequenceDiagram
actor Client
participant Server
participant Middleware
participant Handler
Client->>Server: 1 Event
Server->>Middleware: 2 Dispatch
Middleware->>Handler: 3 Forward
Handler->>Middleware: 4 Return
Middleware->>Server: 5 Return
Server->>Client: 6 Response
Sayangnya, pada Golang Web tidak tersedia middleware namun karena struktur handler yang baik menggunakan interface maka kita bisa membuat middleware sendiri menggunakan handler.
Contoh Implementasi Middleware
Baiklah kita akan coba membuat middleware log pada projek yang sudah kita buat sebelumnya. Buat file log_middleware.go terlebih dahulu lalu isi file tersebut dengan kode dibawah ini.
type LogMiddleware struct {
Handler http.Handler
}
func (middleware *LogMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Println("Before Execute Handler")
middleware.Handler.ServeHTTP(w, r)
fmt.Println("After Execute Handler")
}
Lalu inisialisasi middleware tersebut sebelum server HTTP dijalankan pada file main.go seperti dibawah ini.
...
...
logMiddleware := new(LogMiddleware)
logMiddleware.Handler = mux
server := http.Server{
Addr: "localhost:8080",
Handler: logMiddleware,
}
Setelah itu lakukan build dan jalankan ulang program yang sudah ditambahkan middleware. Maka program tersebut harusnya ketika diakses suatu halaman akan mencetak log pada terminal seperti dibawah ini.
➜ learn-golang-web git:(main) ✗ go build && ./learn-golang-web
Before Execute Handler
After Execute Handler
Before Execute Handler
After Execute Handler
Error Handler
Middleware juga bisa kita gunakan untuk melakukan error handler sehingga jika terjadi panic pada Handler kita bisa melakukan recover di middleware dan mengubah panic tersebut menjadi error response. Maka, dengan ini kita bisa menjaga agar aplikasi kita tidak akan berhenti dan terus berjalan seperti semula.
Misalkan kita buat fungsi handler panic seperti dibawah ini
mux.HandleFunc("/panic", func(w http.ResponseWriter, r *http.Request) {
panic("upps")
})
Dan program akan berhenti dan terjadi panic pada program kita.
➜ learn-golang-web git:(main) ✗ go build && ./learn-golang-web
Before Execute Handler
2023/09/30 15:28:34 http: panic serving 127.0.0.1:55818: upps
goroutine 38 [running]:
net/http.(*conn).serve.func1(0x140001cc000)
/opt/homebrew/Cellar/go/1.17.5/libexec/src/net/http/server.go:1802 +0xdc
panic({0x10265bee0, 0x1026b5768})
/opt/homebrew/Cellar/go/1.17.5/libexec/src/runtime/panic.go:1052 +0x2ac
main.main.func4({0x1026be490, 0x14000170000}, 0x14000156100)
/Users/ihsanarif/Documents/ihsan/tutorial/learn-golang-web/main.go:66 +0x38
net/http.HandlerFunc.ServeHTTP(0x1026b4760, {0x1026be490, 0x14000170000}, 0x14000156100)
/opt/homebrew/Cellar/go/1.17.5/libexec/src/net/http/server.go:2047 +0x40
net/http.(*ServeMux).ServeHTTP(0x14000194300, {0x1026be490, 0x14000170000}, 0x14000156100)
/opt/homebrew/Cellar/go/1.17.5/libexec/src/net/http/server.go:2425 +0x18c
main.(*LogMiddleware).ServeHTTP(0x1400018e180, {0x1026be490, 0x14000170000}, 0x14000156100)
/Users/ihsanarif/Documents/ihsan/tutorial/learn-golang-web/log_middleware.go:14 +0x9c
net/http.serverHandler.ServeHTTP({0x140001c8000}, {0x1026be490, 0x14000170000}, 0x14000156100)
/opt/homebrew/Cellar/go/1.17.5/libexec/src/net/http/server.go:2879 +0x444
net/http.(*conn).serve(0x140001cc000, {0x1026bf6a0, 0x1400018a960})
/opt/homebrew/Cellar/go/1.17.5/libexec/src/net/http/server.go:1930 +0xb6c
created by net/http.(*Server).Serve
/opt/homebrew/Cellar/go/1.17.5/libexec/src/net/http/server.go:3034 +0x4b8
Bagaimana akan bisa menangani panic handler dan error handler tersebut menggunakan Middleware? Berikut ini kita akan coba membuat middleware error handler. Pertama kita buat file error_middleware.go lalu isi file tersebut dengan dibawah ini.
func (middleware *ErrorMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
defer func() {
err := recover()
fmt.Println("recover :", err)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(w, "Error: %v", err)
}
}()
middleware.Handler.ServeHTTP(w, r)
}
Lalu update middleware yang tadi pernah kita tambahkan pada file main.go menjadi seperti dibawah ini.
logMiddleware := new(LogMiddleware)
logMiddleware.Handler = mux
errMiddleware := &ErrorMiddleware{
Handler: logMiddleware,
}
server := http.Server{
Addr: "localhost:8080",
Handler: errMiddleware,
}
Terakhir kita build dan jalankan ulang program tersebut lalu coba akses halaman browser dengan URL
http://localhost:8080/panic
Maka akan muncul pada halaman yang diakses seperti dibawah ini

Dan pada program kita pun tidak akan terjadi panic yang menyebabkan program kita berhenti.
➜ learn-golang-web git:(main) ✗ go build && ./learn-golang-web
Before Execute Handler
recover : upps
Before Execute Handler
After Execute Handler
recover : <nil>