Skip to content

Middleware

Di CodeIgniter 3, untuk menjalankan kode sebelum atau sesudah controller, kamu menggunakan Hooks. Di GoIgniter, konsep ini lebih modern dan fleksibel dengan 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
│ │ └───────┘ │ │
│ └───────────┘ │
└─────────────────┘
Response

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")
}

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"},
}))

Menangkap panic dan mengembalikan error 500 (bukan crash):

app.Use(middleware.Recovery())
// Tanpa recovery: panic = server mati
// Dengan recovery: panic = response 500, server tetap jalan

Menghandle Cross-Origin Resource Sharing untuk API:

app.Use(middleware.CORS())

Membatasi jumlah request per IP:

app.Use(middleware.RateLimit())

Berlaku untuk semua routes:

app.Use(middleware.Logger()) // Semua request di-log
app.Use(middleware.Recovery()) // Semua panic ditangkap

Berlaku hanya untuk routes dalam group tertentu:

// Public routes - tanpa auth
app.GET("/", homeHandler)
app.GET("/products", listProducts)
// Admin routes - dengan auth
admin := app.Group("/admin", AuthMiddleware())
admin.GET("/dashboard", dashboard) // Butuh login
admin.GET("/users", adminUsers) // Butuh login

Perbandingan dengan CI3 Hooks:

application/hooks/Auth_hook.php
<?php
class 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'
);
middleware/auth.go
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 group
admin := app.Group("/admin", AuthMiddleware())
// Atau untuk route tertentu
app.GET("/profile", AuthMiddleware()(profileHandler))

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)
}
}
}
// Penggunaan
app.Use(AuthWithConfig(AuthConfig{
LoginURL: "/auth/login",
ExcludePath: []string{"/", "/about", "/contact"},
}))

Middleware juga bisa didefinisikan di level controller:

type AdminController struct {
core.Controller
}
// Middleware untuk semua method di controller ini
func (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{})
}

Untuk middleware yang hanya berlaku di method tertentu:

type ProductController struct {
core.Controller
}
// Middleware untuk method tertentu saja
func (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
}

Middleware dijalankan sesuai urutan registrasi:

app.Use(middleware.Logger()) // 1. Pertama masuk, terakhir keluar
app.Use(middleware.Recovery()) // 2. Kedua masuk
app.Use(AuthMiddleware()) // 3. Ketiga masuk, pertama keluar

Middleware untuk keamanan sudah siap. Sekarang tinggal tampilkan datanya! Lanjut ke Template Engine.