Episode ini membedah sistem middleware Echo: cara menulis middleware sendiri dengan c.Next, pemasangan di root, group, dan route, pre-middleware dengan e.Pre, serta middleware bawaan seperti RequestLogger, CORS, JWT, BodyLimit, Gzip, dan RateLimit.

Middleware adalah tulang punggung aplikasi Echo. Hampir semua cross-cutting concern — logging, autentikasi, kompresi, pembatasan — hidup di middleware, bukan di dalam handler. Menguasai cara menulis dan memasang middleware akan mengubah cara kalian memandang arsitektur aplikasi.
Episode 6 ini membedah sistem middleware Echo: cara menulis middleware dengan c.Next(), pemasangan di root, group, dan route, pre-middleware dengan e.Pre, serta middleware bawaan yang paling sering dipakai di production.
Middleware adalah fungsi yang membungkus handler dan mengembalikan handler baru. Intinya ada di c.Next() — titik tempat kontrol diteruskan ke handler berikutnya di rantai:
func requestTimer() echo.MiddlewareFunc {
return func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
start := time.Now()
err := next(c)
slog.Info("durasi", "path", c.Path(), "durasi", time.Since(start))
return err
}
}
}Kode sebelum next(c) berjalan saat request masuk; kode setelahnya berjalan saat respons kembali. c.Path() mengembalikan pola route (bukan URL aktual), berguna untuk agregasi.
Middleware bisa dipasang di empat level dengan cakupan berbeda:
e.Use(requestTimer())
admin := e.Group("/admin", middleware.BasicAuth(authFunc))
e.GET("/public", publicHandler, requestTimer())e.Use berlaku untuk semua route.group.Use hanya untuk route di dalam group.e.Pre menjalankan middleware sebelum routing dilakukan. Ini berguna untuk normalisasi yang harus terjadi sebelum router mencocokkan path:
e.Pre(middleware.RemoveTrailingSlash())
e.Pre(middleware.AddTrailingSlash())Perbedaan praktisnya: e.Use berjalan setelah router memilih route, sedangkan e.Pre berjalan sebelum pencocokan. Gunakan e.Pre untuk hal yang mengubah path request itu sendiri, dan e.Use untuk logika yang bergantung pada route terpilih.
Keduanya sudah kalian pasang di episode 3: RequestLogger mencatat setiap request dengan slog, dan Recover mengubah panic menjadi respons 500. Dua middleware ini adalah dasar minimum aplikasi production.
Saat API dipanggil browser dari origin berbeda, CORS diperlukan:
e.Use(middleware.CORSWithConfig(middleware.CORSConfig{
AllowOrigins: []string{"https://app.example.com"},
AllowMethods: []string{http.MethodGet, http.MethodPost},
AllowHeaders: []string{echo.HeaderContentType},
}))Konfigurasi CORS ini membatasi origin, metode, dan header yang diizinkan. Di production, jangan memakai AllowOrigins: ["*"] untuk endpoint yang membawa kredensial.
JWT memvalidasi token di setiap request yang dilindungi. Detail lengkap ada di episode 13, tapi pengenalan dasar:
e.Use(middleware.JWTWithConfig(middleware.JWTConfig{
SigningKey: []byte("rahasia-jwt"),
ContextKey: "user",
}))Setelah middleware ini, request tanpa token valid akan ditolak sebelum mencapai handler.
Dua middleware yang sering dipasang berdampingan: BodyLimit membatasi ukuran body untuk mencegah penyalahgunaan, dan Gzip mengompresi respons untuk menghemat bandwidth:
e.Use(middleware.BodyLimit("1M"))
e.Use(middleware.GzipWithConfig(middleware.GzipConfig{
Level: 5,
}))Nilai "1M" berarti body maksimal satu megabyte. Gzip akan otomatis mengompresi respons yang berukuran cukup besar.
RateLimit melindungi API dari ledakan request. Echo menyediakan store in-memory yang cukup untuk instance tunggal:
e.Use(middleware.RateLimiterWithConfig(middleware.RateLimiterConfig{
Store: middleware.NewRateLimiterMemoryStore(20),
}))Konfigurasi di atas mengizinkan 20 request per detik per identitas. Untuk aplikasi multi-instance, store harus diganti dengan solusi terdistribusi seperti Redis — akan dibahas di episode 19.
Kadang middleware tidak perlu berjalan untuk semua route. Setiap middleware bawaan menerima Skipper untuk mengecualikan path tertentu:
e.Use(middleware.GzipWithConfig(middleware.GzipConfig{
Skipper: func(c echo.Context) bool {
return strings.HasPrefix(c.Path(), "/images/")
},
}))Fungsi Skipper mengembalikan true jika middleware harus dilewati. Ini memberi kalian kendali granular tanpa harus memindahkan middleware ke level route.
Episode 6 membuat kalian menguasai sistem middleware Echo: menulis middleware dengan c.Next(), memasangnya di root, group, dan route, memakai e.Pre untuk tahap sebelum routing, serta memanfaatkan middleware bawaan CORS, JWT, BodyLimit, Gzip, dan RateLimit beserta Skipper untuk kontrol fleksibel.
Inti yang harus dibawa pulang:
c.Next() meneruskan kontrol.next berjalan saat masuk, setelah next saat kembali.e.Use, group.Use, dan middleware route punya cakupan berbeda.e.Pre berjalan sebelum routing, untuk normalisasi path.BodyLimit membatasi ukuran body, Gzip mengompresi respons.RateLimit melindungi API dari ledakan request.Skipper mengecualikan middleware untuk route tertentu.Di episode 7 selanjutnya kita akan membahas response, rendering & static files — pengiriman JSON, XML, dan HTML, template engine dengan renderer custom, streaming respons, penyajian file statis, upload file, serta langkah keamanan StaticDirectoryHandler terkait CVE-2026-55677.