Belajar ExpressJS - Request & Response Handling
Episode 6 of 28

Belajar ExpressJS - Request & Response Handling

Membedah objek request dan response Express: params query body headers ip, metode json send status redirect format, serta cookies, untuk membangun endpoint dengan response lengkap yang benar dan konsisten.

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

Pendahuluan

Setelah di episode 5 kalian merakit stack middleware, episode 6 masuk ke alat komunikasi utama tiap handler: objek req dan res. Dua objek inilah jembatan antara client dan logika aplikasi kalian — semua yang kalian tulis di handler adalah manipulasi keduanya.

Mengapa episode ini penting? Karena endpoint yang bagus bukan hanya soal logika bisnis, tetapi juga kontrak komunikasi: status code yang tepat, response body yang konsisten, header yang benar, dan penanganan cookies yang aman. Konsumen API kalian akan bergantung pada konsistensi ini — sebuah API yang sesekali mengembalikan error sebagai string dan sesekali sebagai JSON akan menyulitkan klien.

Request: Membaca Apa yang Datang

Kita sudah mengenal req.params (episode 4) dan req.body (episode 5). Berikut properti lain yang penting:

PropertiIsiContoh
req.methodMetode HTTPGET
req.pathPath saja, tanpa query/users/42
req.ipIP client (perlu trust proxy di belakang LB)203.0.113.5
req.headersSemua header, key lowercasereq.headers.authorization
req.get(name)Header tunggalreq.get("Content-Type")
req.cookiesCookie ter-parse (butuh cookie-parser)req.cookies.session

Membaca Header

Header otorisasi adalah contoh penggunaan paling umum:

JSMembaca header authorization
app.get("/me", (req, res) => {
  const auth = req.get("Authorization") || ""
  res.json({ hasToken: auth.startsWith("Bearer ") })
})

Perhatikan req.headers.authorization (lowercase) — objek headers selalu menormalkan nama header ke lowercase. Header yang tidak ada bernilai undefined, jadi selalu beri fallback agar handler tidak crash.

Response: Mengirim yang Keluar

status(), json(), send()

Tiga metode paling dasar bekerja berurutan — res.status() menetapkan status, lalu json()/send() mengirim body:

JSResponse JSON dengan status
app.get("/users/:id", (req, res) => {
  const id = Number(req.params.id)
 
  if (!Number.isInteger(id) || id < 1) {
    return res.status(400).json({
      error: "BAD_REQUEST",
      message: "id harus bilangan bulat positif",
    })
  }
 
  res.status(200).json({
    id,
    name: "Budi",
    role: "admin",
  })
})

Perbedaan res.json(data) vs res.send(data): json selalu mengirim Content-Type: application/json dan men-serialize objek, sedangkan send menyimpulkan tipe — objek dikirim sebagai JSON, string sebagai teks. Gunakan json() untuk API agar kontrak tipe konsisten.

redirect()

Memindahkan client ke URL lain — dipakai setelah aksi yang mengubah state (pola PRG/Post-Redirect-Get):

JSRedirect setelah aksi
app.post("/users", (req, res) => {
  const newId = 101
  res.redirect(303, `/users/${newId}`)
})

Status 303 (See Other) adalah pilihan yang tepat setelah POST karena memaksa client melakukan GET — menghindari resubmit form saat refresh.

Content Negotiation: res.format()

Express bisa memilih representasi response sesuai header Accept client:

JSres.format untuk konten berbeda
app.get("/report", (req, res) => {
  res.format({
    "application/json": () => res.json({ ok: true }),
    "text/plain": () => res.send("ok"),
    default: () => res.status(406).end(),
  })
})

Client yang mengirim Accept: application/json mendapat JSON; yang lain mendapat teks; yang tidak cocok mendapat 406 Not Acceptable. Fitur ini jarang dipakai, tetapi berguna untuk API yang melayani banyak jenis konsumen.

Cookies

Cookie perlu middleware cookie-parser agar otomatis ter-parse:

Install cookie-parser
npm install cookie-parser
JSMembaca dan menulis cookie
import cookieParser from "cookie-parser"
 
app.use(cookieParser())
 
app.get("/theme", (req, res) => {
  const theme = req.cookies.theme || "light"
  res.json({ theme })
})
 
app.post("/theme", (req, res) => {
  res.cookie("theme", req.body.theme, {
    httpOnly: false,
    sameSite: "lax",
    maxAge: 30 * 24 * 60 * 60 * 1000,
  })
  res.json({ saved: true })
})

res.cookie(name, value, options) mengirim header Set-Cookie. Opsi httpOnly: true mencegah akses JavaScript (wajib untuk cookie session — episode 12), dan sameSite: "lax" membatasi cookie dikirim lintas situs (perlindungan CSRF — episode 18).

Signed Cookies

cookie-parser mendukung tanda tangan agar isi cookie tidak bisa dipalsukan tanpa secret:

JSSigned cookie
app.use(cookieParser(process.env.COOKIE_SECRET))
 
app.post("/pref", (req, res) => {
  res.cookie("lang", "id", { signed: true })
  res.end()
})
 
app.get("/pref", (req, res) => {
  res.json({ lang: req.signedCookies.lang })
})

Cookie yang ditandatangani dibaca dari req.signedCookies. Ini bukan enkripsi — isi masih bisa dibaca, tapi tamper akan terdeteksi dan nilai ditolak.

Warning

Jangan pernah menyimpan data sensitif (token, password, data pribadi) pada cookie tanpa enkripsi. Signed cookie hanya memastikan integritas, bukan kerahasiaan. Untuk sesi rahasia, simpan data di server dan kirim hanya identifier acak ke client — pola yang dibahas di episode 12.

Endpoint dengan Response Lengkap

Menggabungkan semua alat di atas dalam satu endpoint yang mengikuti kontrak konsisten:

JSEndpoint lengkap: pembuatan user
app.post("/users", (req, res) => {
  const { name, email } = req.body || {}
 
  if (!name || !email) {
    return res.status(422).json({
      error: "VALIDATION_ERROR",
      message: "name dan email wajib diisi",
    })
  }
 
  const user = { id: Date.now(), name, email }
 
  res
    .status(201)
    .location(`/users/${user.id}`)
    .json({ data: user })
})

Perhatikan tiga hal: body divalidasi minimal, error punya bentuk objek yang konsisten, dan response sukses memakai 201 plus header Location. Inilah "kontrak" yang akan terus kita perbaiki di episode 7 (error) dan episode 13 (validasi).

Common Pitfalls

Mengirim Response Dua Kali

Memanggil res.json() lalu res.send() lagi memicu ERR_HTTP_HEADERS_SENT. Gunakan return sebelum mengirim response dalam branch validasi.

Header Sudah Terkirim Sebelum Validasi

Selalu validasi sebelum memanggil metode res apa pun. Setelah res.status().json() dieksekusi, mengubah status tidak berpengaruh lagi.

Tip

Jadikan bentuk error konsisten sejak awal: { error: "KODE", message: "pesan" }. Saat error handler terpusat dibangun di episode 7, kalian hanya perlu menyesuaikan satu lapisan, bukan seratus handler.

Penutup

Episode 6 melengkapi alat komunikasi handler: membaca seluruh sudut req (params, query, body, headers, ip, cookies) dan mengirim response dengan status, json, send, redirect, format, serta cookies biasa dan signed.

Inti yang harus dibawa pulang:

  • req.params/query/body/headers/ip adalah gerbang data masuk; header selalu lowercase.
  • res.status().json() adalah kombinasi utama untuk API; gunakan res.send hanya untuk teks.
  • res.redirect(303, url) mencegah resubmit setelah POST.
  • Cookie dibaca via req.cookies (butuh cookie-parser); signed cookie via req.signedCookies.
  • Bentuk error yang konsisten ({ error, message }) disiapkan sejak awal.

Di episode 7 selanjutnya kita akan membangun error handling — middleware error empat argumen, async error handling otomatis Express 5, dan centralized error handler yang akan dipakai seluruh aplikasi. Sampai jumpa di episode 7!

Belajar ExpressJS - Request & Response Handling | Belajar ExpressJS