Menyisipkan logika di lapisan HTTP dengan custom middleware, membuka akses API ke browser lewat konfigurasi CORS yang benar, membatasi host sah dengan TrustedHost, dan menerapkan pola log-request terpusat.

Setelah di episode 10 aplikasi kita sudah punya test yang solid, sekarang kita bicara tentang hal yang dirasakan setiap klien di lapisan HTTP: middleware. Middleware adalah lapisan yang berjalan sebelum request masuk ke routing dan sesudah response keluar dari handler.
Mengapa episode ini penting? Dua masalah paling umum di produksi FastAPI — "kenapa browser menolak API saya?" (CORS) dan "kenapa ada request mencurigakan ke domain saya?" (host spoofing) — dua-duanya dijawab di episode ini. Middleware juga menjadi tempat yang tepat untuk logging terpusat, kompresi, dan rate limiting di episode 19.
Middleware membungkus aplikasi seperti lingkaran konsentris: request masuk lewat middleware terluar sampai handler, response mengalir balik lewat jalur yang sama:
Di FastAPI, middleware paling sederhana adalah fungsi dengan pola "call next":
import time
from fastapi import FastAPI, Request
app = FastAPI()
@app.middleware("http")
async def log_request(request: Request, call_next):
start = time.perf_counter()
response = await call_next(request)
duration_ms = (time.perf_counter() - start) * 1000
response.headers["X-Process-Time"] = f"{duration_ms:.2f}"
return responsecall_next(request) meneruskan request ke lapisan berikutnya (handler) dan mengembalikan response. Kode sebelum call_next jalan sebelum handler; kode sesudahnya jalan setelah handler selesai. Di sini kita mengukur durasi dan menyisipkannya ke header response.
Tip
Mengukur durasi request adalah pola observability yang akan kita perdalam di episode 17 dan 25. Header X-Process-Time juga bisa dikirim ke log monitoring agar tim bisa melihat endpoint mana yang lambat.
Alternatif idiomatis: gunakan BaseHTTPMiddleware dan daftarkan via app.add_middleware — cara yang sama untuk middleware bawaan:
from starlette.middleware.base import BaseHTTPMiddleware
from fastapi import FastAPI, Request
class SimpleAuthMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next):
if request.url.path.startswith("/internal"):
return JSONResponse({"detail": "forbidden"}, status_code=403)
return await call_next(request)
app = FastAPI()
app.add_middleware(SimpleAuthMiddleware)Pola ini berguna saat middleware perlu menyimpan state atau konstruktor berparameter. Urutan pendaftaran menentukan urutan eksekusi — add_middleware paling akhir didaftarkan, paling luar dijalankan.
CORS (Cross-Origin Resource Sharing) adalah aturan browser: ketika JavaScript dari origin A memanggil API di origin B, server harus mengumumkan bahwa itu diizinkan. Tanpa CORS yang benar, frontend kalian akan ditolak browser meski API berfungsi sempurna.
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
origins = [
"http://localhost:3000",
"https://devvnull.vercel.app",
]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)Aturan penting yang sering diabaikan:
allow_origins sebaiknya daftar eksplisit, bukan ["*"], apalagi saat allow_credentials=True. Browser menolak kombinasi wildcard + credentials.allow_methods=["*"] mengizinkan semua method; bisa dipersempit ke ["GET", "POST", "PUT", "DELETE"].OPTIONS untuk kalian.Caution
allow_origins=["*"] dengan allow_credentials=True bukan hanya tidak bekerja di browser — kombinasi itu juga berbahaya: secara semantik kalian mengklaim API bisa diakses dari origin mana pun sambil membawa cookie. Selalu daftarkan origin nyata. CORS bukan pengganti autentikasi; ia hanya gerbang browser.
Serangan Host header poisoning terjadi saat attacker mengirim request dengan Host palsu, yang bisa meracuni cache, password reset link, atau password reset token. Perlindungannya satu lapis: TrustedHostMiddleware:
from fastapi.middleware.trustedhost import TrustedHostMiddleware
app.add_middleware(
TrustedHostMiddleware,
allowed_hosts=[
"devvnull.vercel.app",
"*.devvnull.vercel.app",
"localhost",
"127.0.0.1",
],
)Request dengan Host di luar daftar langsung ditolak 400 — sebelum menyentuh handler mana pun.
Warning
Jika kalian memakai reverse proxy seperti Nginx (episode 24), wajib tambahkan allowed_hosts yang benar. Proxy akan meneruskan request dengan Host asli; daftar yang salah akan memblokir seluruh trafik sah kalian sendiri.
TrustedHost → CORS → custom middleware (logging, rate limit) → RouterPertimbangan urutan: TrustedHost paling luar (tolah host sebelum apa pun), CORS menangani preflight, lalu middleware bisnis seperti logging/rate limiting — rate limiting di luar logging agar request terbatas tidak boros log.
| Pitfall | Solusi |
|---|---|
| CORS wildcard + credentials | Daftar origin eksplisit |
| Lupa menangani preflight OPTIONS | CORSMiddleware menanganinya otomatis |
| Middleware memblokir request sah | Review urutan & kondisi path |
| Host header spoofing | Tambahkan TrustedHostMiddleware |
Inti yang harus dibawa pulang:
call_next adalah gerbang handler.add_middleware untuk middleware bawaan; @app.middleware("http") untuk fungsi cepat.Di episode 12 selanjutnya kita akan membahas authentication dengan OAuth2 & JWT — alur password flow, hashing password yang aman, pembuatan dan verifikasi token JWT, serta proteksi route dengan dependency. Di sinilah API kalian benar-benar tahu siapa pemakainya!