Middleware Integration - NexaUi Documentation

Middleware Integration

info

Middleware adalah lapisan perantara yang memungkinkan Anda untuk memfilter HTTP request dan response dalam aplikasi NexaUi.

Apa itu Middleware?

Middleware adalah mekanisme untuk memfilter HTTP request yang masuk ke aplikasi Anda. Middleware dapat digunakan untuk berbagai tugas seperti:

  • Autentikasi dan otorisasi
  • Logging request
  • CORS (Cross-Origin Resource Sharing)
  • Validasi input
  • Kompresi response
  • Dan banyak lagi

Cara Kerja Middleware

Middleware bekerja seperti lapisan bawang, di mana request harus melewati setiap lapisan sebelum mencapai controller, dan response harus melewati lapisan yang sama dalam urutan terbalik sebelum dikirim kembali ke client.

Middleware Flow Diagram
Alur request melalui middleware dalam NexaUi

Membuat Middleware

Untuk membuat middleware di NexaUi, Anda perlu membuat class yang mengimplementasikan interface MiddlewareInterface:


namespace App\Middleware;

use App\System\Http\Request;
use App\System\Http\Response;
use App\System\Middleware\MiddlewareInterface;
use App\System\Http\RequestHandler;

class AuthMiddleware implements MiddlewareInterface
{
    public function process(Request $request, RequestHandler $handler): Response
    {
        // Periksa apakah pengguna sudah login
        if (!$this->isAuthenticated()) {
            // Redirect ke halaman login jika belum login
            return new RedirectResponse('/login');
        }
        
        // Lanjutkan ke middleware berikutnya atau controller
        return $handler->handle($request);
    }
    
    private function isAuthenticated(): bool
    {
        return isset($_SESSION['user_id']);
    }
}
                

Mendaftarkan Middleware

Ada beberapa cara untuk mendaftarkan middleware di NexaUi:

1. Global Middleware

Middleware global akan dijalankan pada setiap request:


// Di file bootstrap atau konfigurasi
$app->addMiddleware(new \App\Middleware\LoggingMiddleware());
$app->addMiddleware(new \App\Middleware\SecurityHeadersMiddleware());
                

2. Route Middleware

Middleware dapat diterapkan pada route tertentu:


// Di file routes/web.php
$router->group(['middleware' => [\App\Middleware\AuthMiddleware::class]], function($router) {
    $router->get('/dashboard', 'DashboardController@index');
    $router->get('/profile', 'ProfileController@show');
});

// Atau pada route individual
$router->get('/admin', 'AdminController@index')
       ->middleware(\App\Middleware\AdminMiddleware::class);
                

3. Controller Middleware

Middleware juga dapat ditambahkan di level controller:


class UserController extends NexaController
{
    protected function init(): void
    {
        parent::init();
        
        // Tambahkan middleware ke semua action di controller ini
        $this->addMiddleware(new \App\Middleware\AuthMiddleware());
        
        // Middleware hanya untuk action tertentu
        $this->addMiddleware(new \App\Middleware\AdminMiddleware(), ['update', 'delete']);
    }
}
                

Middleware Groups

Anda dapat mengelompokkan beberapa middleware menjadi satu grup untuk memudahkan penggunaan:


// Di file konfigurasi middleware
$app->middlewareGroups([
    'web' => [
        \App\Middleware\StartSession::class,
        \App\Middleware\VerifyCsrfToken::class,
    ],
    'api' => [
        \App\Middleware\ThrottleRequests::class,
        \App\Middleware\FormatJsonResponse::class,
    ]
]);

// Penggunaan di routes
$router->group(['middleware' => 'web'], function($router) {
    // Routes dengan middleware web group
});

$router->group(['middleware' => 'api'], function($router) {
    // Routes dengan middleware api group
});
                

Middleware Priority

Urutan middleware sangat penting karena menentukan urutan eksekusi. Middleware yang didaftarkan lebih awal akan dieksekusi lebih dulu:


// Urutan eksekusi: LoggingMiddleware -> AuthMiddleware -> RateLimitMiddleware
$app->addMiddleware(new \App\Middleware\LoggingMiddleware()); // Dieksekusi pertama
$app->addMiddleware(new \App\Middleware\AuthMiddleware()); // Dieksekusi kedua
$app->addMiddleware(new \App\Middleware\RateLimitMiddleware()); // Dieksekusi ketiga
                

Anda juga dapat menentukan prioritas secara eksplisit:


$app->addMiddleware(new \App\Middleware\CriticalMiddleware(), null, 100); // Prioritas tinggi
$app->addMiddleware(new \App\Middleware\NormalMiddleware(), null, 50); // Prioritas normal
$app->addMiddleware(new \App\Middleware\LowPriorityMiddleware(), null, 10); // Prioritas rendah
                

Contoh Middleware Umum

Authentication Middleware


namespace App\Middleware;

class AuthMiddleware implements MiddlewareInterface
{
    public function process(Request $request, RequestHandler $handler): Response
    {
        if (!isset($_SESSION['user_id'])) {
            return new RedirectResponse('/login');
        }
        
        return $handler->handle($request);
    }
}
                

CORS Middleware


namespace App\Middleware;

class CorsMiddleware implements MiddlewareInterface
{
    public function process(Request $request, RequestHandler $handler): Response
    {
        $response = $handler->handle($request);
        
        return $response->withHeaders([
            'Access-Control-Allow-Origin' => '*',
            'Access-Control-Allow-Methods' => 'GET, POST, PUT, DELETE, OPTIONS',
            'Access-Control-Allow-Headers' => 'Content-Type, Authorization'
        ]);
    }
}
                

Rate Limiting Middleware


namespace App\Middleware;

class RateLimitMiddleware implements MiddlewareInterface
{
    private $maxRequests = 60;
    private $timeWindow = 60; // dalam detik
    
    public function process(Request $request, RequestHandler $handler): Response
    {
        $ip = $request->getClientIp();
        $key = "rate_limit:{$ip}";
        
        $count = $this->getRequestCount($key);
        
        if ($count >= $this->maxRequests) {
            return new JsonResponse([
                'error' => 'Too many requests'
            ], 429);
        }
        
        $this->incrementRequestCount($key);
        
        return $handler->handle($request);
    }
    
    // Implementasi metode helper
}
                

Terminable Middleware

Beberapa middleware mungkin perlu melakukan operasi setelah response dikirim ke client. Untuk ini, Anda dapat menggunakan interface TerminableMiddlewareInterface:


namespace App\Middleware;

use App\System\Http\Request;
use App\System\Http\Response;
use App\System\Middleware\TerminableMiddlewareInterface;

class LoggingMiddleware implements MiddlewareInterface, TerminableMiddlewareInterface
{
    public function process(Request $request, RequestHandler $handler): Response
    {
        // Catat waktu mulai
        $startTime = microtime(true);
        
        // Proses request
        $response = $handler->handle($request);
        
        // Simpan waktu mulai di response
        $response = $response->withAttribute('start_time', $startTime);
        
        return $response;
    }
    
    public function terminate(Request $request, Response $response): void
    {
        // Operasi ini dijalankan setelah response dikirim ke client
        $startTime = $response->getAttribute('start_time');
        $duration = microtime(true) - $startTime;
        
        // Log durasi request
        $this->logger->info(sprintf(
            'Request to %s completed in %.2fms',
            $request->getUri()->getPath(),
            $duration * 1000
        ));
    }
}
                

Best Practices

  • Middleware harus mengikuti Single Responsibility Principle - satu middleware untuk satu tugas
  • Gunakan middleware untuk logika yang perlu dijalankan pada banyak route
  • Pertimbangkan urutan middleware dengan hati-hati
  • Hindari operasi yang berat di middleware global
  • Gunakan middleware group untuk mengelompokkan middleware yang sering digunakan bersama
  • Tulis unit test untuk middleware penting

Contoh Implementasi Lengkap

Berikut adalah contoh implementasi lengkap dari middleware dalam aplikasi NexaUi:


// system/Middleware/MiddlewareInterface.php
namespace App\System\Middleware;

use App\System\Http\Request;
use App\System\Http\Response;
use App\System\Http\RequestHandler;

interface MiddlewareInterface
{
    public function process(Request $request, RequestHandler $handler): Response;
}

// system/Middleware/MiddlewareStack.php
namespace App\System\Middleware;

use App\System\Http\Request;
use App\System\Http\Response;
use App\System\Http\RequestHandler;

class MiddlewareStack implements RequestHandler
{
    private $middlewares = [];
    private $controller;
    private $action;
    private $params;
    
    public function __construct(callable $controller, string $action, array $params = [])
    {
        $this->controller = $controller;
        $this->action = $action;
        $this->params = $params;
    }
    
    public function addMiddleware(MiddlewareInterface $middleware): self
    {
        $this->middlewares[] = $middleware;
        return $this;
    }
    
    public function handle(Request $request): Response
    {
        if (empty($this->middlewares)) {
            return $this->processController($request);
        }
        
        $middleware = array_shift($this->middlewares);
        return $middleware->process($request, $this);
    }
    
    private function processController(Request $request): Response
    {
        $controller = $this->controller;
        $action = $this->action;
        $params = $this->params;
        
        return $controller->$action(...$params);
    }
}

// Penggunaan di bootstrap aplikasi
$app->run(function($request) use ($router) {
    $route = $router->match($request->getMethod(), $request->getUri()->getPath());
    
    if (!$route) {
        return new Response('Not Found', 404);
    }
    
    $controller = new $route['controller']();
    $action = $route['action'];
    $params = $route['params'];
    
    $stack = new MiddlewareStack($controller, $action, $params);
    
    // Tambahkan global middleware
    foreach ($app->getMiddlewares() as $middleware) {
        $stack->addMiddleware($middleware);
    }
    
    // Tambahkan route middleware
    foreach ($route['middleware'] as $middlewareClass) {
        $stack->addMiddleware(new $middlewareClass());
    }
    
    // Proses request melalui middleware stack
    return $stack->handle($request);
});
                
warning

Middleware yang kompleks dapat memengaruhi performa aplikasi. Gunakan profiling tools untuk mengidentifikasi bottleneck.