Server adalah program yang menunggu pertanyaan dan menjawabnya. Bayangin loket informasi di stasiun: petugas duduk di loket nomor 3000 dan menunggu. Tiap orang datang membawa pertanyaan, petugas menjawab, lalu menutup dengan "sudah ya". Di Node, pertanyaan itu request, jawabannya response, nomor loketnya port, dan "sudah ya" adalah res.end(). Semua itu ada di modul bawaan http.
🧪 Tebakan cepat: handler-mu memanggil
res.writeHead(200, ...)tapi lupares.end(). Apa yang dialami browser atau curl yang bertanya? Tebak dulu, jawabannya ada di bagian "res.end(): jawabannya selesai".
Membuat server dengan http.createServer
Proyek catatan-api sekarang menjawab lewat jaringan. Buat file server.js:
const http = require("node:http");
const catatan = [
{ id: 1, judul: "Belanja", isi: "beli beras 5 kg" },
{ id: 2, judul: "Belajar", isi: "bab Node.js" },
];
const server = http.createServer((req, res) => {
console.log(req.method + " " + req.url);
if (req.method === "GET" && req.url === "/catatan") {
res.writeHead(200, { "Content-Type": "application/json" });
res.end(JSON.stringify(catatan));
return;
}
res.writeHead(404, { "Content-Type": "application/json" });
res.end(JSON.stringify({ error: "Tidak ditemukan" }));
});
server.listen(3000, () => {
console.log("Server jalan di http://localhost:3000");
});
http.createServer(handler)membuat server. Functionhandlerdipanggil sekali untuk tiap request yang datang.req(request) berisi pertanyaannya:req.method("GET","POST", ...) danreq.url(path yang diminta).res(response) adalah alat untuk menjawab.res.writeHead(200, {...})menentukan status code dan header."Content-Type": "application/json"memberi tahu penerima bahwa isinya JSON.res.end(JSON.stringify(catatan))mengirim isi jawabannya (body) lalu menutupnya. Body harus teks, jadi array diubah dulu denganJSON.stringify.returnmenghentikan handler supaya baris 404 di bawahnya gak ikut jalan.server.listen(3000, ...)mulai menunggu di port 3000. Callback-nya jalan sekali, saat server siap.
Mencoba server-nya
Jalankan node server.js. Bedanya dengan script biasa: program ini gak selesai, dia terus menunggu request sampai kamu menekan Ctrl+C. Buka terminal kedua dan tanya dengan curl -i (-i ikut menampilkan header):
$ curl -i http://localhost:3000/catatan
HTTP/1.1 200 OK
Content-Type: application/json
Date: Thu, 08 Oct 2026 03:00:00 GMT
Connection: keep-alive
Keep-Alive: timeout=5
Transfer-Encoding: chunked
[{"id":1,"judul":"Belanja","isi":"beli beras 5 kg"},{"id":2,"judul":"Belajar","isi":"bab Node.js"}]
Baris pertama adalah status: 200 OK. Lalu header: Content-Type dari kodemu, sisanya ditambahkan Node sendiri. Setelah baris kosong, body-nya. Di terminal pertama, server mencetak GET /catatan. Membuka http://localhost:3000/catatan di browser juga memberi JSON yang sama.
Membaca method dan URL
Server ini cuma menjawab GET /catatan. Sisanya dapat 404:
| Request | req.method |
req.url |
Status |
|---|---|---|---|
GET /catatan |
"GET" |
"/catatan" |
200 |
POST /catatan |
"POST" |
"/catatan" |
404 |
GET /catatan?urut=judul |
"GET" |
"/catatan?urut=judul" |
404 |
Baris terakhir sering bikin bingung: req.url membawa query string (bagian setelah ?), jadi gak sama dengan "/catatan". Ambil path-nya saja dengan new URL(req.url, "http://localhost").pathname, hasilnya "/catatan".
res.end(): jawabannya selesai
Tanpa res.end(), jawabannya gak pernah dikirim. Node bahkan menahan status dan header-nya, jadi yang bertanya gak menerima apa pun dan terus menunggu: request-nya menggantung. Browser memutar ikon loading, dan curl yang dibatasi 5 detik menyerah:
$ curl -i -m 5 http://localhost:3000/catatan
curl: (28) Operation timed out after 5002 milliseconds with 0 bytes received
Itu jawaban tebakannya. Tiap jalur di handler harus berakhir dengan tepat satu res.end().
Di latihan: server tanpa request sungguhan
Simulator latihan gak mengirim request ke server-mu, jadi baris jawabannya dicetak dari object yang sama. Yang kamu tulis: require("http"), http.createServer, di dalam callback res.writeHead(200, { "Content-Type": "application/json" }) lalu res.end(JSON.stringify({ message: "Halo dari Node.js!" })). Output-nya:
Server dibuat!
Response: {"message":"Halo dari Node.js!"}
Kenapa nanti pakai Express
Server ini baru punya satu route, dan sudah butuh if untuk method, path, dan query. Puluhan route berarti puluhan if, ditambah membaca body JSON sendiri. Express, di pelajaran berikutnya, mengurus semua itu di atas modul http yang sama.
⚠️ Jebakan yang sering ketemu
- Lupa
res.end(). Request menggantung sampai yang bertanya menyerah. - Lupa
returnsetelah menjawab. Kode jalan terus keres.writeHead(404, ...), dan Node melemparError [ERR_HTTP_HEADERS_SENT]: Cannot write headers after they are sent to the client. Error yang gak ditangkap mematikan seluruh server, jadi request berikutnya dapatcurl: (7) Failed to connect to localhost port 3000. - Mengirim object ke
res.end.res.end({ pesan: "halo" })melemparTypeError [ERR_INVALID_ARG_TYPE]. Ubah dulu denganJSON.stringify. - Port sudah dipakai. Menjalankan
node server.jsdua kali memberiError: listen EADDRINUSE: address already in use :::3000. Matikan yang lama dengan Ctrl+C. - Kode berubah, server lama masih jalan. Node membaca
server.jssekali saat menyala. Setelah mengedit, matikan dan jalankan lagi, atau pakainode --watch server.jsyang restart sendiri.
TL;DR: http.createServer((req, res) => {...}) membuat server yang memanggil handler sekali untuk tiap request, dan server.listen(3000) mulai menunggu di port 3000. Baca req.method dan req.url (ingat, req.url ikut membawa query string). Jawab dengan res.writeHead(status, { "Content-Type": "application/json" }) lalu res.end(JSON.stringify(data)). Tanpa res.end(), request menggantung. Tiap jalur menjawab tepat sekali, jadi return setelah menjawab, kalau gak, ERR_HTTP_HEADERS_SENT mematikan server.