Express adalah framework HTTP yang dibangun di atas modul http Node.js dan menyediakan abstraksi rute, middleware, serta helper respons yang ringkas. Topik ini membahas pembuatan aplikasi Express pertama, pendefinisian rute untuk berbagai method HTTP, pembacaan parameter jalur (req.params) dan query string (req.query), serta pengiriman respons JSON. Setelah membaca topik ini, sebuah server HTTP minimal dapat dibangun dengan Express dan bagian dinamis pada URL dapat dibaca dengan benar.
Aplikasi Express pertama#
Sebuah aplikasi Express dimulai dari pemanggilan express() yang menghasilkan objek app. Objek app adalah instance dari fungsi middleware Express, sehingga dapat dipasang sebagai listener http.createServer atau dipanggil langsung oleh app.listen. Metode app.listen(port) membungkus http.createServer(app) dan menjalankan server pada port yang diberikan. Bila port diberi nilai 0, sistem operasi memilih port bebas, yang berguna untuk pengujian otomatis.
Rute didefinisikan dengan app.METHOD(path, handler), di mana METHOD adalah nama method HTTP dalam huruf kecil (get, post, put, delete, dan seterusnya) dan handler menerima (req, res). Objek req membungkus permintaan masuk, sedangkan res membungkus respons yang akan dikirim. Pemanggilan res.json(obj) mengirim respons JSON dengan Content-Type yang sesuai secara otomatis.
Berikut aplikasi Express paling ringkas: satu rute GET / yang mengembalikan JSON, dijalankan pada port acak, lalu diakses memakai fetch bawaan Node 24. Berkas app.js di bawah dijalankan oleh blok bash berikutnya dengan NODE_PATH mengarah ke direktori tempat Express dipasang di sandbox.
// tidak-dijalankan: butuh Express yang dipasang di /tmp/dasar-express
const express = require('express');
const app = express();
app.get('/', (req, res) => {
res.json({ pesan: 'halo', versi: process.version });
});
const server = app.listen(0, async () => {
const port = server.address().port;
const r = await fetch(`http://127.0.0.1:${port}/`);
const body = await r.text();
console.log('status:', r.status);
console.log('content-type:', r.headers.get('content-type'));
console.log('body:', body);
server.close();
});
server.on('close', () => {
console.log('server ditutup');
});# pasang Express sekali untuk demo topik ini: cd /tmp/dasar-express && npm install express
# jalankan app.js dari direktori topik, NODE_PATH mengarah ke node_modules demo
NODE_PATH=/tmp/dasar-express/node_modules node app.jsstatus: 200
content-type: application/json; charset=utf-8
body: {"pesan":"halo","versi":"v24.22.2"}
server ditutupKeluaran tersebut memperlihatkan tiga hal. res.json menetapkan Content-Type: application/json; charset=utf-8 tanpa konfigurasi tambahan, status respons default adalah 200, dan server ditutup setelah permintaan dijawab sehingga proses Node dapat kelihatan bersih. Pemakaian port 0 membuat demo tidak bentrok dengan layanan lain di mesin yang sama.
Rute dan method HTTP#
Express mencocokkan permintaan masuk terhadap daftar rute berdasarkan method dan pola jalur. Method yang didukung sebagai metode pada app mencakup get, post, put, patch, delete, head, dan options. Setiap rute memanggil handler pertama yang cocok, sehingga dua rute dengan method berbeda pada jalur yang sama adalah hal yang lazim.
// tidak-dijalankan: fragmen, bukan berkas utuh
app.get('/catatan', (req, res) => res.json({ aksi: 'daftar' }));
app.post('/catatan', (req, res) => res.status(201).json({ aksi: 'buat' }));
app.put('/catatan/:id', (req, res) => res.json({ aksi: 'ganti', id: req.params.id }));
app.delete('/catatan/:id', (req, res) => res.status(204).end());Handler boleh berbentuk fungsi biasa atau async. Pada Express 5, penolakan promise dari handler async diteruskan otomatis ke middleware penanganan error, sehingga try/catch tidak wajib untuk setiap handler. Topik tersendiri membahas pola itu lebih jauh.
Parameter jalur dan query string#
Bagian dinamis pada jalur ditandai dengan tanda titik dua, misalnya /users/:id. Express menangkap segmen yang cocok dan menyimpannya pada req.params sebagai pasangan kunci-nilai string. Bila beberapa segmen dinamis dipakai, masing-masing menjadi properti sendiri pada req.params, sehingga /users/:userId/catatan/:catatanId menghasilkan { userId, catatanId }.
Query string, yaitu bagian setelah tanda tanya pada URL, diuraikan otomatis dan disimpan pada req.query. Parameter yang muncul sekali menjadi string, sedangkan parameter yang muncul beberapa kali menjadi larik. Penguraian default tidak mengubah tipe data, sehingga nilai aktif=true tetap berupa string "true" dan bukan boolean.
// tidak-dijalankan: butuh Express yang dipasang di /tmp/dasar-express
const express = require('express');
const app = express();
app.get('/users/:id', (req, res) => {
res.json({
params: req.params,
query: req.query,
});
});
const server = app.listen(0, async () => {
const port = server.address().port;
const r = await fetch(
`http://127.0.0.1:${port}/users/42?aktif=true&tag=a&tag=b`
);
console.log('status:', r.status);
console.log('body:', await r.text());
server.close();
});# jalankan dari direktori topik
NODE_PATH=/tmp/dasar-express/node_modules node params-query.jsstatus: 200
body: {"params":{"id":"42"},"query":{"aktif":"true","tag":["a","b"]}}Keluaran memperlihatkan dua perilaku kunci. req.params.id berisi "42" sebagai string, bukan angka, sehingga konversi tipe eksplisit diperlukan bila pembandingan numerik ingin dilakukan. req.query.tag berupa larik ["a","b"] karena tag muncul dua kali pada query string, sedangkan req.query.aktif berupa string "true" karena hanya muncul sekali.
Konsekuensi praktis dari penguraian ini adalah bahwa query string tidak boleh dipakai untuk keputusan keamanan tanpa validasi. Nilai aktif=true bukan boolean true, dan parameter id dari jalur bukan angka. Validasi dengan pustaka skema seperti zod atau ajv mengubah string hasil penguraian menjadi tipe yang diharapkan dan menolak masukan yang tidak sah.
Mengirim respons#
Objek res menyediakan beberapa helper untuk mengirim respons sesuai tipe yang dimaksud. res.json(value) mengirim JSON dengan Content-Type yang sesuai, res.send(body) mengirim teks atau buffer dengan deteksi Content-Type berdasarkan tipe argumen, res.status(code) menetapkan kode status HTTP, dan res.end() mengakhiri respons tanpa badan. Pemanggilan res.status(204).end() adalah idiom untuk respons sukses tanpa badan.
Helper res mengembalikan res itu sendiri pada sebagian besar metode, sehingga beberapa pemanggilan dapat digabung dalam satu pernyataan. Kombinasi yang umum dipakai adalah res.status(201).json(obj) untuk respons buat sukses, res.status(400).json({ error }) untuk permintaan tidak valid, dan res.status(404).end() untuk sumber daya yang tidak ada tanpa badan.
// tidak-dijalankan: fragmen, bukan berkas utuh
res.json({ nama: 'Ali' }); // 200 application/json
res.status(201).json({ dibuat: true }); // 201 application/json
res.send('teks polos'); // 200 text/html
res.status(400).send('permintaan tidak valid');
res.status(204).end(); // 204 tanpa badan
Kesalahan umum#
Membandingkan req.params.id langsung dengan angka. Nilai pada req.params selalu berupa string, sehingga req.params.id === 42 selalu bernilai false. Lakukan konversi eksplisit, misalnya Number(req.params.id) === 42, atau validasi melalui pustaka skema sebelum membandingkan.
Mengabaikan urutan pendaftaran rute. Express mencocokkan rute sesuai urutan app.get/app.post/app.use dipanggil. Rute statis app.get('/baru', ...) yang didaftarkan setelah app.get('/:id', ...) tidak akan pernah cocok untuk path /baru karena :id lebih dulu menangkap segmen tersebut. Daftarkan rute yang lebih spesifik lebih dulu, atau kelompokkan dengan express.Router.
Lupa menutup server pada skrip demo. app.listen membuka socket yang mempertahankan event loop, sehingga proses Node tidak keluar sampai server.close() dipanggil. Pada pengujian otomatis, panggil server.close() setelah asersi selesai agar proses berikutnya dapat berjalan.
Ringkasan#
- Objek
appdariexpress()adalah fungsi middleware yang dapat dijalankan langsung olehapp.listen, dengan rute didefinisikan melaluiapp.METHOD(path, handler). req.paramsmenyimpan segmen dinamis dari pola jalur (misalnya:id) sebagai string, sedangkanreq.querymenyimpan hasil penguraian query string dengan parameter berulang menjadi larik.- Helper respons
res.json,res.send,res.status, danres.endmencakup kombinasi tipe badan dan kode status HTTP yang lazim dipakai. - Urutan pendaftaran rute menentukan rute mana yang cocok lebih dulu, sehingga rute spesifik perlu didaftarkan sebelum rute yang lebih umum.
Referensi#
- Express — Hello World — Express.js
— Contoh resmi aplikasi Express pertama beserta
app.listen. - Express — Routing — Express.js
— Penjelasan resmi
app.METHOD, parameter rute, dan query string. - Express 5.x API — Express.js
— Referensi API lengkap
app,req, danrespada Express 5.