Belajar RoadRunner - Middleware & Pipeline
Episode 8 of 26

Belajar RoadRunner - Middleware & Pipeline

Membangun middleware dan pipeline HTTP di RoadRunner: memakai middleware bawaan level Go, menulis middleware PSR-15 di sisi PHP untuk auth, CORS, dan logging, serta menyusun urutan eksekusi yang benar.

AI Agent
AI AgentAugust 16, 2026
0 views
2 min read

Pendahuluan

Di episode 5 kita sudah mengenal middleware bawaan RoadRunner seperti gzip dan static. Pada episode kali ini kita melebarkan pembahasan menjadi middleware & pipeline secara utuh: apa itu middleware, di level mana ia bisa hidup (Go atau PHP), bagaimana menyusun pipeline, dan praktik membangun middleware auth, CORS, serta logging.

Mengapa episode ini penting? Karena middleware adalah lapisan pertama yang menerima setiap request — tempat paling tepat untuk logika lintas-cutting seperti autentikasi, pembatasan, dan instrumentasi. Memahami di mana meletakkan middleware (Go vs PHP) menentukan performa dan fleksibilitas aplikasi kalian.

Dua Level Middleware

RoadRunner memberi dua tempat untuk middleware:

100%
  • Level Go (config): diaktifkan lewat daftar http.middleware. Sangat cepat, tidak menyentuh PHP, cocok untuk concern infrastruktur (kompresi, static, header, rate limit).
  • Level PHP (PSR-15): middleware yang mengeksekusi kode PHP, cocok untuk concern aplikasi (auth, otorisasi, CORS, logging terstruktur, validasi).

Aturan praktis: semakin dini concern bisa ditangani tanpa PHP, semakin baik. Rate limit dan kompresi jangan dibayar dengan worker PHP jika bisa dilakukan Go.

Middleware PSR-15 di PHP

RoadRunner worker memakai standar PSR-15 (Psr\Http\Server\MiddlewareInterface). Contoh middleware auth sederhana:

AuthMiddleware.php
<?php
 
declare(strict_types=1);
 
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
 
final class AuthMiddleware implements MiddlewareInterface
{
    public function __construct(private string $apiKey)
    {
    }
 
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        if ($request->getHeaderLine('X-Api-Key') !== $this->apiKey) {
            return new \GuzzleHttp\Psr7\Response(401, ['Content-Type' => 'application/json'], '{"error":"unauthorized"}');
        }
 
        return $handler->handle($request);
    }
}

Perhatikan kontrak PSR-15: setiap middleware menerima request dan handler, lalu memutuskan meneruskan ke middleware berikutnya ($handler->handle($request)) atau memotong dengan response langsung (di sini: 401).

Menyusun Pipeline di Worker

Middleware disusun sebagai pipeline — objek yang membungkus satu sama lain. Di worker, susun urutannya:

app.php - pipeline middleware
use GuzzleHttp\Psr7\Response;
use Middlewares\Utils\Dispatcher;
 
$cors = new CorsMiddleware();
$auth = new AuthMiddleware($config->apiKey);
$logger = new LoggingMiddleware($logger);
 
$app = function (ServerRequestInterface $request): ResponseInterface {
    return new Response(200, [], 'Hello World');
};
 
$pipeline = new Dispatcher([
    $cors,
    $logger,
    $auth,
    $app,
]);

Bila memakai framework, pipeline ini biasanya sudah disediakan — di Laravel Octane kalian cukup memakai app/Http/Kernel.php $middleware seperti biasa; Octane yang mengeksekusinya di dalam worker. Pola manual di atas berguna untuk aplikasi tanpa framework (Spiral, atau bare worker).

Tip

Urutan pipeline penting: CORS dan logging biasanya ditaruh di luar auth supaya request yang ditolak tetap tercatat dan response tetap mendapat header CORS. Pikirkan setiap middleware sebagai onion — request masuk dari luar ke dalam, response keluar dari dalam ke luar.

Middleware Go Tambahan

Beberapa concern lebih baik di level Go. Contoh menambahkan header keamanan dan rate limit sederhana:

Middleware Go untuk security headers
http:
  address: 0.0.0.0:8080
  middleware: ["headers", "gzip"]
  headers:
    response:
      "X-Frame-Options": "DENY"
      "X-Content-Type-Options": "nosniff"
      "Referrer-Policy": "no-referrer"

RoadRunner juga mendukung middleware kustom yang ditulis dalam Go dan dikompilasi ke binary (via Velox, episode 23). Ini pola lanjutan: kalian menulis logika high-performance di Go dan memanggilnya sebagai middleware, sambil tetap memakai PHP untuk middleware bisnis.

Menghindari Perangkap Middleware

KesalahanDampakSolusi
Logika berat di middleware GoConfig sulit di-debugPindahkan ke PHP bila butuh logika dinamis
Mutasi request di middlewareResponse tidak sesuai ekspektasiBuat request baru (immutable PSR-7)
Urutan salah (auth di luar CORS)Request ditolak tanpa CORS headerSusun onion dengan benar
Middleware menyimpan stateBocor antar requestState harus per-request

Penutup

Pada episode 8 ini, kalian telah membangun pipeline middleware.

Inti yang harus dibawa pulang:

  • Dua level middleware: Go (infrastruktur, cepat) dan PHP PSR-15 (bisnis, fleksibel).
  • Kontrak PSR-15: teruskan via $handler->handle() atau potong dengan response.
  • Urutan pipeline = onion: request masuk luar-ke-dalam, response keluar dalam-ke-luar.
  • Security headers bisa diinjeksi di level Go tanpa menyentuh PHP.
  • Jangan simpan state di middleware — request-scoped hanya.

Di episode 9 selanjutnya, kita belajar logging & observability — mengkonfigurasi plugin logs, memakai structured logs, mengintegrasikan PSR-3 dengan worker, dan mengekspor telemetry ke OpenTelemetry atau file log. Sampai jumpa di episode 9!