Menu
CoddyTech

Middleware sebagai Decorator

Termasuk bagian Pemrograman Berorientasi Objek dalam perjalanan GO di Coddy. Pelajaran 97 dari 107.

Middleware adalah salah satu penerapan pola Decorator yang paling praktis di Go. Dalam pengembangan web, fungsi middleware membungkus handler HTTP untuk menambahkan kebutuhan lintas fungsi seperti pencatatan log, autentikasi, atau pengukuran waktu tanpa mengubah handler aslinya.

Inti utamanya adalah middleware menerima handler dan mengembalikan handler baru dengan perilaku tambahan. Ini mengikuti pola Decorator secara tepat: antarmuka yang sama saat masuk dan keluar, dengan fungsionalitas yang ditingkatkan:

type Handler func(request string) string

func LoggingMiddleware(next Handler) Handler {
    return func(request string) string {
        result := next(request)
        return "[LOG] " + result
    }
}

func AuthMiddleware(next Handler) Handler {
    return func(request string) string {
        return "[AUTH] " + next(request)
    }
}

Setiap middleware membungkus handler berikutnya dalam rantai, lalu menambahkan perilakunya sebelum atau sesudah memanggil handler yang dibungkus. Kamu dapat menyusun beberapa middleware secara berurutan:

func MainHandler(request string) string {
    return "Response to: " + request
}

handler := LoggingMiddleware(AuthMiddleware(MainHandler))
fmt.Println(handler("GET /users"))
// [LOG] [AUTH] Respons untuk: GET /users

Urutan pembungkusan menentukan urutan eksekusi: middleware terluar dijalankan terlebih dahulu. Pola ini banyak digunakan dalam framework web Go untuk pipeline pemrosesan permintaan, sehingga memudahkan penambahan atau penghapusan fungsionalitas tanpa menyentuh logika inti handler.

challenge icon

Tantangan

Mudah

Mari buat pipeline pemrosesan request menggunakan pola Middleware sebagai Decorator! Kamu akan membuat sistem tempat fungsi middleware membungkus handler untuk menambahkan fungsionalitas seperti pencatatan waktu, validasi, dan pemformatan, semuanya tanpa mengubah logika inti handler.

Kamu akan mengatur kodemu dalam tiga file:

  • handler.go: Tentukan tipe handler dan handler dasar yang memproses request.

    Buat tipe Handler sebagai fungsi yang menerima string request dan mengembalikan string respons:

    type Handler func(request string) string

    Implementasikan fungsi BaseHandler yang mengembalikan Processed: [request] untuk setiap request yang diterimanya.

  • middleware.go: Buat fungsi middleware yang membungkus handler dengan perilaku tambahan.

    Buat tiga fungsi middleware, yang masing-masing menerima Handler dan mengembalikan Handler baru:

    • TimingMiddleware: membungkus respons dengan info waktu, lalu mengembalikan [TIMING] [response]
    • ValidationMiddleware: menambahkan prefiks validasi, lalu mengembalikan [VALID] [response]
    • UppercaseMiddleware: mengubah seluruh respons menjadi huruf kapital

    Setiap middleware harus memanggil handler yang dibungkusnya dan menyempurnakan hasilnya.

  • main.go: Bangun pipeline pemrosesan dengan menyusun middleware.

    Baca jumlah lapisan middleware yang akan diterapkan. Lalu, untuk setiap lapisan, baca tipe middleware (timing, validation, atau uppercase) dan bungkus handler saat ini dengan middleware tersebut. Terapkan middleware sesuai urutan pembacaannya: middleware pertama yang dibaca menjadi pembungkus terluar.

    Setelah membangun pipeline, baca string request, proses melalui handler yang telah kamu susun, lalu cetak hasilnya.

Input berikut akan diberikan:

  • Baris 1: Jumlah lapisan middleware
  • Baris berikutnya: Satu tipe middleware per baris (timing, validation, atau uppercase)
  • Baris terakhir: Request yang akan diproses

Contohnya, untuk input:

2
timing
validation
GET /users

Output-mu seharusnya:

[TIMING] [VALID] Processed: GET /users

Untuk input:

3
uppercase
timing
validation
POST /data

Output-mu seharusnya:

[TIMING] [VALID] PROCESSED: POST /DATA

Untuk input:

1
uppercase
hello world

Output-mu seharusnya:

PROCESSED: HELLO WORLD

Untuk input:

0
simple request

Output-mu seharusnya:

Processed: simple request

Perhatikan bagaimana urutan pembungkusan middleware memengaruhi output: middleware pertama yang diterapkan (terluar) berjalan pertama dan menerima hasil akhir dari semua middleware di dalamnya. Middleware uppercase pada contoh kedua berjalan terakhir (paling dalam), sehingga mengubah respons dasar menjadi huruf kapital sebelum timing dan validation menambahkan prefiksnya!

Coba sendiri

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	reader := bufio.NewReader(os.Stdin)

	// Baca jumlah lapisan middleware
	nLine, _ := reader.ReadString('\n')
	n, _ := strconv.Atoi(strings.TrimSpace(nLine))

	// Baca jenis middleware
	middlewareTypes := make([]string, n)
	for i := 0; i < n; i++ {
		line, _ := reader.ReadString('\n')
		middlewareTypes[i] = strings.TrimSpace(line)
	}

	// Baca permintaan
	request, _ := reader.ReadString('\n')
	request = strings.TrimSpace(request)

	// TODO: Mulai dengan BaseHandler

	// TODO: Bangun pipeline dengan membungkus handler menggunakan middleware
	// Terapkan middleware secara berurutan, middleware yang dibaca pertama menjadi pembungkus terluar
	// Petunjuk: Lakukan perulangan pada middlewareTypes dalam urutan TERBALIK untuk mencapai ini
	// Middleware yang diterapkan terakhir akan menjadi yang terluar (berjalan lebih dulu)

	// TODO: Proses permintaan melalui handler yang telah disusun dan cetak hasilnya
	fmt.Println("TODO: implement pipeline")
}
quiz iconUji dirimu

Pelajaran ini berisi kuis singkat. Mulai pelajarannya untuk menjawab kuis dan melacak progresmu.

Semua pelajaran di Pemrograman Berorientasi Objek

Latihan sendiri: Compiler Go online