Belajar Chi - Subrouters, Groups & Mounting
Episode 5 of 23

Belajar Chi - Subrouters, Groups & Mounting

Episode ini mengajarkan cara mengorganisasi route dalam skala besar: subrouter dengan r.Route, group yang berbagi middleware dengan r.Group, dan mount sub-app dengan r.Mount. Kalian juga belajar memisahkan resource router dan menerapkan middleware per subrouter secara selektif.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Pendahuluan

Aplikasi nyata tidak pernah cukup dengan satu file router. Episode 5 mengajarkan struktur yang membuat route tetap rapi saat aplikasi tumbuh: subrouters, groups, dan mounting. Tiga mekanisme ini adalah cara chi mengelola kompleksitas tanpa memperkenalkan tipe handler baru.

Pola yang akan kalian kuasai di sini menjadi kerangka seluruh struktur project di episode 8. Jika kalian pernah pusing dengan middleware yang tidak jalan di sebagian route, jawabannya hampir selalu ada di episode ini.

Subrouter dengan r.Route

Memisahkan Prefix

r.Route membuat router anak yang mewarisi middleware router induk dan hidup di bawah satu prefix:

Subrouter /api
func main() {
    r := chi.NewRouter()
    r.Use(middleware.Logger)
 
    r.Route("/api", func(api chi.Router) {
        api.Get("/ping", func(w http.ResponseWriter, req *http.Request) {
            w.Write([]byte("pong"))
        })
        api.Get("/health", healthHandler)
    })
 
    http.ListenAndServe(":8080", r)
}

Semua route di dalam r.Route("/api", ...) otomatis berada di bawah /api. api.Get("/ping", handler) menghasilkan endpoint /api/ping. Router anak mewarisi middleware.Logger dari induk tanpa harus mendaftar ulang.

Subrouter Bersarang

Resource bisa dipecah lebih dalam dengan route bersarang:

Subrouter bersarang
r.Route("/users", func(users chi.Router) {
    users.Get("/", listUsers)
    users.Post("/", createUser)
    users.Route("/{id}", func(user chi.Router) {
        user.Get("/", getUser)
        user.Put("/", updateUser)
        user.Delete("/", deleteUser)
    })
})

Struktur ini mencerminkan hierarki URL: /users, /users/42, /users/42 dengan method berbeda. user.Get("/", getUser) di dalam subrouter /{id} menangani /users/42.

Group dengan r.Group

Middleware Berbagi Tanpa Prefix

r.Group membuat scope baru yang memakai middleware tertentu tanpa mengubah path:

Group dengan middleware bersama
r.Group(func(admin chi.Router) {
    admin.Use(middleware.BasicAuth("app",
        map[string]string{"admin": "rahasia"}))
    admin.Get("/admin/stats", statsHandler)
})
 
r.Get("/public", publicHandler)

Group admin memakai Basic Auth, sedangkan route /public yang berada di luar group tidak terpengaruh. r.Group(func(admin chi.Router){:go}... adalah cara memilah area yang butuh proteksi berbeda tanpa prefix terpisah.

Kapan Memakai Group

Gunakan r.Group ketika:

  • Area berbeda membutuhkan middleware berbeda di path yang sama.
  • Kalian ingin menerapkan middleware hanya untuk beberapa route.
  • Kalian butuh sub-scope sementara tanpa memindahkan seluruh route.

Gunakan r.Route ketika path-nya memang berbeda dan ingin dibersihkan dari prefix berulang.

Mount Sub-app

Memasang Router Mandiri

r.Mount menempelkan router lain — bahkan milik orang lain — sebagai handler di bawah prefix:

Mount sub-app v1
func main() {
    r := chi.NewRouter()
 
    v1 := chi.NewRouter()
    v1.Use(middleware.Recoverer)
    v1.Get("/status", statusHandler)
 
    r.Mount("/v1", v1)
    http.ListenAndServe(":8080", r)
}

r.Mount("/v1", v1) membuat seluruh route di v1 dapat diakses lewat /v1/status. Router v1 berdiri sendiri dengan middleware Recoverer-nya sendiri — bukan turunan dari r.

Mount Handler Bukan Router

Karena Mount menerima http.Handler, kalian bisa menempel apa saja:

Mount handler lain
fileServer := http.FileServer(http.Dir("./static"))
r.Mount("/assets", http.StripPrefix("/assets", fileServer))

http.StripPrefix("/assets", fileServer) menghapus prefix sebelum diteruskan ke file server — pola ini akan kita pakai lagi di episode 7 untuk file statis.

Organisasi Resource Router

Memisahkan ke Fungsi

Untuk project nyata, pindahkan setiap resource ke fungsi router sendiri:

Router resource terpisah
func usersRouter() http.Handler {
    users := chi.NewRouter()
    users.Get("/", listUsers)
    users.Post("/", createUser)
    users.Route("/{id}", func(user chi.Router) {
        user.Get("/", getUser)
        user.Put("/", updateUser)
    })
    return users
}
 
func main() {
    r := chi.NewRouter()
    r.Mount("/users", usersRouter())
    r.Mount("/products", productsRouter())
    http.ListenAndServe(":8080", r)
}

usersRouter() dan productsRouter() masing-masing mengembalikan http.Handler, lalu di-mount ke root. Setiap resource kini berdiri sendiri dan mudah diuji.

Reuse Middleware per Subrouter

Middleware Seleksi

Kombinasi With dan subrouter memberi kontrol middleware yang presisi:

Middleware selektif
r.Route("/api", func(api chi.Router) {
    api.Use(middleware.Throttle(100))
 
    api.Route("/admin", func(admin chi.Router) {
        admin.Use(middleware.BasicAuth("app",
            map[string]string{"root": "s3cret"}))
        admin.Get("/dashboard", dashboardHandler)
    })
 
    api.With(middleware.Compress(5)).Get("/export", exportHandler)
})

api.With(middleware.Compress(5)).Get("/export", ...) menerapkan middleware inline hanya untuk satu route — pola yang disebut inline middleware, dan diperkuat lagi di versi 5.3 seperti akan kita bahas di episode 20.

Penutup

Inti yang harus dibawa pulang:

  • r.Route membuat subrouter dengan prefix dan mewarisi middleware induk.
  • r.Group membatasi scope middleware tanpa mengubah path.
  • r.Mount menempelkan router atau handler lain sebagai sub-app.
  • Resource router bisa dipecah ke fungsi yang mengembalikan http.Handler.
  • With memberi middleware inline per route.
  • Kombinasi ketiganya membuat struktur aplikasi besar tetap terpelihara.

Di episode 6 selanjutnya kita fokus pada tulang punggung chi: middleware dan chain — menulis middleware sendiri, memakai r.Use, merangkai dengan middleware.Chain, dan menjelajahi middleware bawaan seperti RequestID, Logger, Recoverer, dan BasicAuth.

Belajar Chi - Subrouters, Groups & Mounting | Belajar Chi