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>