pemrograman

19 HTTP Middleware

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

tutorial golang web panic error middleware

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>
comments powered by Disqus