Episode ini melebarkan logika gateway dengan kode: custom routing hooks dan plugin-based decision logic, aksi domain-specific yang memperpanjang 9router, serta modul rute yang bisa dipakai ulang lintas project.

Episode 15 membuat gateway cepat dan hemat. Tapi sekuat apa pun, config YAML tetap punya batas: logika routing bawaan tidak selalu tahu bahwa "request dari dashboard member premium harus diutamakan di antrean" atau "jawaban untuk customer service perlu menyisipkan data pelanggan dari sistem internal". Untuk kasus seperti ini, 9router membuka pintu menuju kode.
Episode 16 memperkenalkan ekstensi: custom routing hooks yang memotong alur keputusan, plugin dengan decision logic sendiri, aksi domain-specific yang memperpanjang kemampuan gateway, dan modul rute yang bisa dipakai ulang di banyak project. Inilah saatnya gateway tidak lagi sekadar menerima — ia bisa berpikir dengan logika kalian.
Hook adalah titik suntikan di sepanjang siklus hidup request. 9router mendefinisikan beberapa titik: sebelum routing (before_route), setelah rute terpilih (after_route), sebelum request dikirim ke provider (before_upstream), dan setelah respons kembali (after_response). Di titik-titik ini kalian bisa membaca konteks, mengubah metadata, atau membatalkan request.
hooks:
- name: prioritize-premium
event: before_route
action: augment_metadata
- name: enforce-business-hours
event: before_route
action: reject_if_closed
- name: log-cost-category
event: after_response
action: emit_logImplementasi hook berupa kode yang mengekspor fungsi dengan konteks request:
export function prioritizePremium(ctx) {
const plan = ctx.request.metadata.plan;
if (plan === "premium") {
ctx.request.metadata.priority = "high";
}
return { action: "continue", ctx };
}Hook yang berubah-ubah sepanjang versi harus punya kebijakan versi tersendiri, sama seperti kebijakan routing di episode 10 — tanda tangani versi hook agar keputusan lama tetap bisa diaudit.
Hook menyuntik satu titik; plugin menggantikan bagian logika yang lebih besar — termasuk pemilihan route itu sendiri. Plugin adalah paket yang bisa diinstal, berisi satu atau lebih function yang dieksekusi 9router pada fase tertentu, dan menawarkan fungsi yang tidak ada di inti.
9router plugin install @9router/plugin-latency-router
9router plugin enable latency-routerexport function decideModel(request) {
const maxLatency = request.metadata.sla_latency_ms;
if (maxLatency && maxLatency < 800) {
return { model: "gpt-4o-mini", reason: "sla_latency" };
}
return { model: "gpt-4o", reason: "default" };
}Plugin latency-router di atas memilih model berdasarkan SLA latensi yang diminta — logika yang tidak masuk akal dihardcode ke config murni. Setiap plugin dijalankan dalam sandbox: akses dibatasi, dan jika plugin error, gateway kembali ke decision logic bawaan alih-alih gagal total.
plugins:
latency-router:
version: "1.4.0"
sandbox: true
fallback: builtin
timeout: 10msDaftar plugin yang aktif dan versinya bisa dicek dengan 9router plugin list.
Selain mengubah keputusan, kalian bisa menambahkan aksi baru yang spesifik untuk domain kalian — hal yang tidak akan pernah ada di 9router bawaan. Contohnya aksi yang mengisi data pelanggan dari CRM sebelum prompt dikirim, atau aksi yang menyisipkan hasil query SQL ke dalam konteks model.
actions:
- name: inject-customer-context
event: before_upstream
inputs:
customer_id: metadata.customer_id
output_field: context.customer_summaryImplementasi aksinya adalah kode biasa yang dipanggil 9router dengan argumen terstruktur:
export async function loadCustomerSummary({ customerId }) {
const res = await fetch(`https://crm.internal/customers/${customerId}`);
if (!res.ok) throw new Error("customer load failed");
return { summary: await res.text(), source: "crm" };
}Hasilnya disuntikkan ke context.customer_summary dan tersedia untuk template prompt route tersebut. Perhatikan keamanannya: aksi memanggil host internal, jadi pastikan host di-allowlist seperti yang dibahas di episode 11, dan semua invocation tercatat di audit tool_invocation dari episode 14.
Warning
Aksi yang memanggil layanan eksternal adalah jalur data baru. Terapkan timeout, retry terbatas, dan fallback: jika CRM sedang mati, lebih baik melewati penyuntikan konteks daripada memblokir seluruh request.
Banyak workflow berulang di semua project: customer support dengan guard, terjemahan dengan format ketat, atau ekstraksi terstruktur dengan schema. Route modules membungkus satu workflow lengkap — rute, guardrail, cache, aksi, dan kebijakan — menjadi satu paket yang bisa di-import ke project mana pun.
route_modules:
- name: support-handoff
version: "2.1.0"
routes:
- support-triage
includes:
- guardrails: [moderation-in, pii-scrub]
- cache: support-cache
- actions: [inject-customer-context]imports:
- module: support-handoff
version: "2.1.0"
overrides:
support-triage:
model: gpt-4o-miniModul memberi konsistensi: tim lain tidak perlu menebak-nebak konfigurasi guard yang benar. overrides memungkinkan penyesuaian lokal tanpa mengubah kode modul. Dengan membungkus rute, guard, aksi, dan kebijakan jadi satu unit, kalian membangun perangkat standar perusahaan — persis yang nantinya menjadi pijakan saat mendokumentasikan standar routing di episode 21.
Episode 16 mengubah 9router dari config murni menjadi platform yang bisa diprogram: custom routing hooks menyuntik logika di titik-titik penting alur request, plugin menggantikan decision logic besar dengan kode bersandbox, aksi domain-specific memperpanjang kemampuan gateway dengan logika bisnis kalian, dan modul rute membungkus workflow lengkap agar bisa dipakai ulang lintas project.
Inti yang harus dibawa pulang:
Gateway kalian kini bisa berpikir dengan logika bisnis sendiri. Di episode 17 kita membawanya ke skala dunia: Distributed & Multi-region Routing — edge routing, pemilihan model regional, pengurangan latensi untuk user global, serta failover multi-region dan redundansi provider. Sampai jumpa di sana!