Membedah middleware Express: built-in seperti express.json urlencoded dan static, third-party seperti cors dan morgan, serta custom middleware untuk logging, dengan fokus pada urutan dan stack parser yang benar.

Setelah di episode 4 kalian menguasai routing, episode 5 membahas komponen yang membuat Express unik: middleware. Konsep yang kita kenalkan di episode 2 kini diwujudkan dalam bentuk nyata — middleware bawaan, middleware third-party, dan middleware custom.
Mengapa middleware harus dikuasai lebih dalam? Karena aplikasi Express pada dasarnya adalah tumpukan middleware. Parser body, autentikasi, logging, CORS, rate limiting, compression — semuanya middleware. Semakin baik kalian memahami pola ini, semakin mudah kalian merakit aplikasi dari blok-blok kecil yang sudah terbukti, alih-alih menulis ulang semuanya dari nol.
| Kategori | Contoh | Asal |
|---|---|---|
| Built-in | express.json, express.urlencoded, express.static | Bundled Express |
| Third-party | cors, morgan, helmet | npm registry |
| Custom | fungsi buatan sendiri | Kode kalian |
Kita akan memakai ketiganya di episode ini dan sepanjang series.
Middleware yang paling sering dipakai — mem-parsing body JSON dan mengisinya ke req.body:
app.use(express.json({ limit: "1mb" }))Tanpa ini, req.body tetap kosong meski client mengirim JSON. Opsi limit: "1mb" membatasi ukuran payload — pertahanan pertama terhadap request raksasa (diperdalam di episode 20).
Mem-parsing body format form (application/x-www-form-urlencoded) — dipakai aplikasi yang menerima submit form HTML:
app.use(express.urlencoded({ extended: true }))extended: true membuat hasil parsing bisa berupa objek bertingkat (memakai parser qs); false memakai parser sederhana yang hanya mendukung pasangan key-value datar.
Menyajikan file statis dari direktori — dipakai untuk asset publik:
app.use(express.static("public"))File public/logo.svg lalu bisa diakses di http://localhost:3000/logo.svg. Kita bahas penuh bersama templating di episode 11.
Browser memberlakukan same-origin policy: fetch dari origin lain (misalnya frontend React di port 5173) diblokir tanpa header CORS. Middleware cors mengaturnya:
npm install corsimport cors from "cors"
app.use(cors())Untuk produksi, konfigurasi CORS harus dibatasi ke daftar origin yang diizinkan — bukan cors() polos yang mengizinkan semua. Ini bagian dari hardening di episode 18.
Logger HTTP yang menampilkan tiap request di konsol:
npm install morganimport morgan from "morgan"
app.use(morgan("dev"))Format "dev" menampilkan metode, URL, status, waktu, dan ukuran response — sempurna untuk development. Format "combined" lebih verbose dan cocok untuk log produksi (episode 17).
Custom middleware hanyalah fungsi (req, res, next) yang dipasang dengan app.use:
const requestTime = (req, res, next) => {
req.requestTime = Date.now()
next()
}
const logger = (req, res, next) => {
const { method, url } = req
const started = Date.now()
res.on("finish", () => {
console.log(`${method} ${url} ${res.statusCode} ${Date.now() - started}ms`)
})
next()
}
app.use(requestTime)
app.use(logger)Perhatikan middleware requestTime memodifikasi req — data tambahan ini bisa dibaca handler di bawahnya (req.requestTime). Pola ini dipakai berat oleh middleware autentikasi di episode 12 (menempelkan req.user).
Middleware yang butuh konfigurasi dibuat lewat fungsi pabrik:
const requireRole = (roles) => (req, res, next) => {
if (!roles.includes(req.user?.role)) {
return res.status(403).json({ error: "Forbidden" })
}
next()
}
app.get("/admin", requireRole(["admin"]), (req, res) => {
res.json({ secret: true })
})Pola ini sangat umum — requireRole(["admin"]) adalah fungsi yang mengembalikan middleware. Kita pakai lagi untuk RBAC di episode 12.
Posisi middleware menentukan perilaku. Contoh stack yang benar:
app.use(morgan("dev")) // 1. logging paling luar
app.use(express.json()) // 2. parsing body
app.use(cors()) // 3. CORS sebelum route
app.use(express.static("public")) // 4. asset statis
// 5. routes
app.use("/api", apiRouter)
// 6. 404 + error handler (episode 7)Middleware yang dipasang sebelum router akan berjalan untuk semua route di dalamnya. Memasang express.json() setelah route berarti body tidak pernah ter-parsing untuk route itu.
morgan dipasang paling awal karena ingin mencatat semua request — termasuk yang ditolak parser body atau CORS. Semakin dalam posisi middleware, semakin sedikit request yang menjangkaunya.
Warning
Memanggil next() dua kali pada middleware yang sama menghasilkan error ERR_HTTP_HEADERS_SENT saat handler di bawahnya mencoba mengirim response kedua. Pastikan setiap middleware memanggil next() tepat sekali — atau mengakhiri response dengan return.
Penyebabnya hampir selalu middleware parser tidak terpasang, atau terpasang setelah route. Cek urutan app.use(express.json()) berada di atas route yang membutuhkannya.
Client yang mengirim Content-Type: text/plain atau form tidak akan ter-parsing oleh express.json(). Pasang urlencoded untuk form dan pastikan client mengirim header yang benar.
Episode 5 memetakan tiga kategori middleware: built-in (express.json, urlencoded, static), third-party (cors, morgan), dan custom yang bisa memodifikasi req. Kalian juga memahami mengapa urutan pemasangan menentukan segalanya.
Inti yang harus dibawa pulang:
express.json, express.urlencoded, express.static.cors untuk kebijakan origin, morgan untuk logging.req (misal req.requestTime) untuk handler di bawahnya.requireRole(roles)) untuk middleware yang bisa dikonfigurasi.Di episode 6 selanjutnya kita akan membedah request & response handling — seluruh properti req (params, query, body, headers, ip) dan metode res (json, send, status, redirect, format) serta cookies, untuk membangun endpoint dengan response lengkap. Sampai jumpa di episode 6!