Express.js 5
  • Bab 3 dari 9
  • 20 menit
  • 4 soal kuis

Middleware

Di bab ini (7 bagian)
  1. Tujuan
  2. Konsep Dasar Middleware
  3. Lima Jenis Middleware di Express
  4. Middleware Bawaan dan File Statis
  5. Menangani Cookie dan CORS
  6. Upload File dengan Multer
  7. Rangkuman

Tujuan bab ini

Di bab ini, kita akan fokus pada beberapa tujuan belajar utama:

  • Memahami konsep alur kerja middleware di dalam Express.
  • Menggunakan middleware bawaan (built-in) dan pihak ketiga (third-party).
  • Menangani cookie, CORS, dan upload file dengan menggunakan Multer.

Konsep Dasar Middleware

Bila diibaratkan, middleware adalah jantung dari Express. Dalam alur kerjanya, middleware merupakan fungsi berantai yang bertugas memproses request sebelum akhirnya mencapai route handler atau mengirimkan response.

Setiap middleware selalu menerima tiga argumen utama, yaitu req (request), res (response), dan next. Fungsi ini memiliki kebebasan untuk membaca atau mengubah objek req dan res. Setelah selesai melakukan tugasnya, middleware memiliki dua pilihan: mengakhiri siklus dengan mengirimkan respons ke klien, atau memanggil fungsi next() untuk meneruskan kendali ke middleware berikutnya di dalam antrean.

Alur Request Middleware

Aturan Penting Middleware

Ada beberapa hal krusial yang perlu kamu ingat saat bekerja dengan middleware:

  • Urutan itu penting: Middleware dieksekusi secara berurutan sesuai dengan kapan mereka didaftarkan menggunakan app.use(). Middleware yang didaftarkan lebih dulu akan dijalankan lebih dulu.
  • Wajib memanggil next(): Jika sebuah middleware tidak mengirimkan respons (misalnya res.send()), ia wajib memanggil next(). Bila kamu lupa memanggil next(), request tersebut akan menggantung (hang) dan klien tidak akan pernah menerima balasan.
  • Menangani error: Jika terjadi kesalahan, kamu bisa memanggil next(err) dengan menyertakan argumen error. Ini akan membuat Express melompat langsung ke error handler, melewati middleware reguler lainnya.

Mari kita lihat contoh kode pembuatan middleware kustom untuk pencatatan log (logger):

const logger = (req, res, next) => {
  const start = Date.now();
  res.on('finish', () => {
    const ms = Date.now() - start;
    console.log(req.method, req.url, res.statusCode, ms + 'ms');
  });
  next(); // lanjut ke middleware berikutnya
};

app.use(logger);

Pada kode di atas, kita mencatat waktu mulai saat request datang. Kita lalu mendengarkan event finish pada response untuk menghitung durasi total. Jangan lupa, di akhir fungsi kita memanggil next() agar alur berlanjut.

Lima Jenis Middleware di Express

Express mengkategorikan middleware menjadi lima jenis berdasarkan cara penggunaannya:

  1. Application-level: Didaftarkan pada instance aplikasi menggunakan app.use(fn). Ini berlaku untuk seluruh aplikasi atau path tertentu.
  2. Router-level: Mirip dengan application-level, tetapi didaftarkan pada instance router menggunakan router.use(fn). Ini hanya berlaku untuk route di dalam router tersebut.
  3. Error-handling: Middleware khusus yang memiliki tepat empat argumen, yaitu (err, req, res, next). Fungsinya untuk menangani semua error yang terjadi di aplikasi.
  4. Built-in: Middleware bawaan yang sudah disediakan oleh Express, seperti express.json(), express.urlencoded(), express.static(), express.raw(), dan express.text().
  5. Third-party: Middleware dari paket npm eksternal yang dipasang terpisah. Contohnya adalah helmet, cors, morgan, dan multer.

Middleware Bawaan dan File Statis

Express datang dengan beberapa middleware bawaan yang sangat berguna untuk mengolah body dari request dan menyajikan file statis.

Parsing Body Request

Untuk membaca data yang dikirimkan oleh klien di dalam body request, kamu harus memasang middleware parser yang sesuai:

  • express.json(): Digunakan untuk mem-parsing body dalam format JSON dan memasukkannya ke req.body. Kamu bisa membatasi ukurannya, misalnya { limit: '1mb' }.
  • express.urlencoded(): Digunakan untuk mem-parsing data dari form HTML reguler ke req.body. Di Express v5, opsi extended secara default bernilai false.
  • express.text() dan express.raw(): Digunakan untuk membaca body sebagai string biasa atau Buffer.

Melayani File Statis

Kamu bisa menyajikan file statis (HTML, CSS, JS, gambar) secara langsung menggunakan express.static(). File dengan awalan titik (dotfiles) akan diabaikan secara otomatis.

Kamu juga bisa memberikan prefix virtual atau jalur buatan pada URL, serta mengatur konfigurasi cache browser.

// File statis dari folder public
app.use(express.static('public', {
  maxAge: '1d', // cache browser
}));

// Prefix virtual
app.use('/assets', express.static('uploads'));

Upload File dengan Multer

Untuk menerima file yang diunggah oleh pengguna (misalnya gambar profil atau dokumen), kita memakai middleware pihak ketiga bernama Multer.

Multer bekerja dengan memproses form dengan tipe multipart/form-data. Kamu bisa mengonfigurasi multer.diskStorage untuk menentukan di mana file akan disimpan (destination) dan bagaimana file tersebut akan dinamai (filename). Sangat disarankan untuk mengubah nama file menggunakan sesuatu yang unik, seperti crypto.randomUUID(), untuk menghindari bentrokan nama.

Multer juga dilengkapi fitur keamanan seperti pembatasan ukuran file (limits: { fileSize: ... }) dan filter tipe file (fileFilter) untuk memastikan pengguna hanya mengunggah format yang diperbolehkan.

import multer from 'multer';
import path from 'node:path';
import crypto from 'node:crypto';

const storage = multer.diskStorage({
  destination: 'uploads/',
  filename: (req, file, cb) => {
    const ext = path.extname(file.originalname);
    cb(null, crypto.randomUUID() + ext);
  }
});

export const upload = multer({
  storage,
  limits: { fileSize: 2 * 1024 * 1024 }, // 2MB
  fileFilter: (req, file, cb) => {
    const ok = ['image/png', 'image/jpeg'].includes(file.mimetype);
    cb(null, ok);
  }
});

Setelah dikonfigurasi, kamu bisa menyisipkan middleware Multer ke route tertentu. Gunakan upload.single('namaField') untuk menerima satu file, yang nanti akan ditaruh di req.file. Jika mengunggah banyak file, gunakan upload.array('namaField', batasMaks) yang mengisi req.files, atau upload.fields([...]) bila file dikirim dari field yang berbeda-beda.

Rangkuman

  • Middleware adalah fungsi perantara yang menerima (req, res, next) dan memproses request secara berurutan.
  • Selalu pastikan middleware memanggil next() agar request tidak menggantung, kecuali middleware tersebut mengakhiri siklus dengan mengirim respons.
  • Gunakan middleware bawaan express.json() dan express.urlencoded() untuk mem-parsing body, serta express.static() untuk menyajikan file HTML atau gambar.
  • Pengelolaan cookie bisa dilakukan dengan cookie-parser dan diatur aman dengan opsi httpOnly, secure, dan sameSite.
  • Izin lintas domain diatur dengan middleware cors(), yang juga otomatis menangani request Preflight.
  • Upload file ditangani menggunakan multer, lengkap dengan fitur penyimpanan kustom, batasan ukuran, dan filter tipe file.

Selesaikan bab ini

  1. 1. Baca materi
  2. 2. Kuis (4 soal)

Cek pemahaman

  1. 1Apa yang akan terjadi jika sebuah middleware tidak mengirimkan respons dan juga lupa memanggil fungsi next()?

  2. 2Berapa banyak argumen yang wajib dimiliki oleh fungsi middleware untuk error-handling di Express?

    app.use((err, req, res, next) => {
      // tangani error
    });
  3. 3Jika kamu mengaktifkan opsi credentials: true pada middleware cors(), kamu boleh mengatur opsi origin menjadi '*' (izinkan semua).

  4. 4Opsi cookie apa yang digunakan untuk mencegah nilai cookie dibaca oleh skrip JavaScript di browser?