Middleware
Di CodeIgniter 3, untuk menjalankan kode sebelum atau sesudah controller, kamu menggunakan Hooks. Di GoIgniter, konsep ini lebih modern dan fleksibel dengan Middleware.
Konsep Middleware
Section titled “Konsep Middleware”Middleware adalah fungsi yang membungkus handler. Ia bisa menjalankan kode sebelum request diproses, sesudahnya, atau keduanya.
Request ↓┌─────────────────┐│ Logger │ ← catat waktu mulai│ ┌───────────┐ ││ │ Recovery │ │ ← tangkap panic│ │ ┌───────┐ │ ││ │ │Handler│ │ │ ← proses request│ │ └───────┘ │ ││ └───────────┘ │└─────────────────┘ ↓ResponseBuilt-in Middleware
Section titled “Built-in Middleware”GoIgniter menyediakan beberapa middleware yang siap pakai:
import "goigniter/system/middleware"
func main() { app := core.New()
// Log setiap request (method, path, duration) app.Use(middleware.Logger())
// Tangkap panic agar server tidak crash app.Use(middleware.Recovery())
// Handle CORS untuk API app.Use(middleware.CORS())
// Batasi request per IP app.Use(middleware.RateLimit())
app.Run(":8080")}Logger
Section titled “Logger”Mencatat setiap request ke console:
app.Use(middleware.Logger())
// Output:// [GET] /products 1.234ms <nil>// [POST] /products 5.678ms <nil>Dengan konfigurasi custom:
app.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{ Format: "[%s] %s %v", SkipPaths: []string{"/health", "/metrics"},}))Recovery
Section titled “Recovery”Menangkap panic dan mengembalikan error 500 (bukan crash):
app.Use(middleware.Recovery())
// Tanpa recovery: panic = server mati// Dengan recovery: panic = response 500, server tetap jalanMenghandle Cross-Origin Resource Sharing untuk API:
app.Use(middleware.CORS())RateLimit
Section titled “RateLimit”Membatasi jumlah request per IP:
app.Use(middleware.RateLimit())Global vs Group Middleware
Section titled “Global vs Group Middleware”Global Middleware
Section titled “Global Middleware”Berlaku untuk semua routes:
app.Use(middleware.Logger()) // Semua request di-logapp.Use(middleware.Recovery()) // Semua panic ditangkapGroup Middleware
Section titled “Group Middleware”Berlaku hanya untuk routes dalam group tertentu:
// Public routes - tanpa authapp.GET("/", homeHandler)app.GET("/products", listProducts)
// Admin routes - dengan authadmin := app.Group("/admin", AuthMiddleware())admin.GET("/dashboard", dashboard) // Butuh loginadmin.GET("/users", adminUsers) // Butuh loginMembuat Middleware Sendiri
Section titled “Membuat Middleware Sendiri”Perbandingan dengan CI3 Hooks:
<?phpclass Auth_hook { public function check_login() { $CI =& get_instance(); if (!$CI->session->userdata('user_id')) { redirect('login'); } }}
// application/config/hooks.php$hook['post_controller_constructor'] = array( 'class' => 'Auth_hook', 'function' => 'check_login', 'filename' => 'Auth_hook.php', 'filepath' => 'hooks');package middleware
import "goigniter/system/core"
func AuthMiddleware() core.Middleware { return func(next core.HandlerFunc) core.HandlerFunc { return func(c *core.Context) error { // Cek session atau token userID := getSessionUserID(c)
if userID == 0 { // Tidak login, redirect ke login page return c.Redirect(302, "/login") }
// Simpan user info untuk dipakai di handler c.Set("user_id", userID)
// Lanjut ke handler berikutnya return next(c) } }}Penggunaan:
// Untuk satu groupadmin := app.Group("/admin", AuthMiddleware())
// Atau untuk route tertentuapp.GET("/profile", AuthMiddleware()(profileHandler))Middleware dengan Konfigurasi
Section titled “Middleware dengan Konfigurasi”Contoh middleware yang bisa dikonfigurasi:
type AuthConfig struct { LoginURL string ExcludePath []string}
func AuthWithConfig(config AuthConfig) core.Middleware { skipPaths := make(map[string]bool) for _, path := range config.ExcludePath { skipPaths[path] = true }
return func(next core.HandlerFunc) core.HandlerFunc { return func(c *core.Context) error { // Skip untuk path tertentu if skipPaths[c.Path()] { return next(c) }
// Cek auth if !isLoggedIn(c) { return c.Redirect(302, config.LoginURL) }
return next(c) } }}
// Penggunaanapp.Use(AuthWithConfig(AuthConfig{ LoginURL: "/auth/login", ExcludePath: []string{"/", "/about", "/contact"},}))Controller-Level Middleware
Section titled “Controller-Level Middleware”Middleware juga bisa didefinisikan di level controller:
type AdminController struct { core.Controller}
// Middleware untuk semua method di controller inifunc (a *AdminController) Middleware() []core.Middleware { return []core.Middleware{ AuthMiddleware(), AdminOnlyMiddleware(), }}
func (a *AdminController) Index() { // Sudah pasti user login dan admin a.Ctx.View("admin/dashboard", core.Map{})}Per-Method Middleware
Section titled “Per-Method Middleware”Untuk middleware yang hanya berlaku di method tertentu:
type ProductController struct { core.Controller}
// Middleware untuk method tertentu sajafunc (p *ProductController) MiddlewareFor() map[string][]core.Middleware { return map[string][]core.Middleware{ "Store": {AuthMiddleware()}, // POST butuh login "Update": {AuthMiddleware()}, // PUT butuh login "Delete": {AuthMiddleware(), AdminOnly()}, // DELETE butuh admin }}
func (p *ProductController) Index() { // Public - tanpa auth}
func (p *ProductController) Store() { // Butuh login}
func (p *ProductController) Delete() { // Butuh login + admin}Urutan Middleware
Section titled “Urutan Middleware”Middleware dijalankan sesuai urutan registrasi:
app.Use(middleware.Logger()) // 1. Pertama masuk, terakhir keluarapp.Use(middleware.Recovery()) // 2. Kedua masukapp.Use(AuthMiddleware()) // 3. Ketiga masuk, pertama keluarMiddleware untuk keamanan sudah siap. Sekarang tinggal tampilkan datanya! Lanjut ke Template Engine.