Di akhir section Data dan Serialization, katalog buku Budi masih dibaca dari data tiruan yang ditulis langsung di berkas contoh. Kini saatnya menggantinya dengan percakapan sungguhan: JavaScript modern menyediakan fetch, satu function bawaan untuk meminta data ke server. Function ini mengembalikan Promise — persis seperti async-await yang kita kuasai di section Asynchronous JavaScript — sehingga tidak ada konsep mesin baru; yang baru hanyalah pihak lawan bicaranya.
Chapter ini membahas tiga hal: bentuk fetch paling sederhana, options untuk mengatur method, header, dan body, serta cara membaca body respons — termasuk satu jebakan yang hampir selalu dialami pemula. Seperti chapter sebelumnya, seluruh contoh memakai server tiruan yang tertanam di berkas contoh, sehingga keluaran bisa Anda hasilkan ulang sendiri dengan node fetch-dasar.mjs tanpa koneksi internet.
Bentuk Dasar: fetch dengan Satu Argumen #
Aturannya sederhana: fetch(url) mengirim permintaan GET ke alamat tersebut dan mengembalikan Promise yang resolve menjadi object Response. Karena fetch butuh waktu (sinyal harus bolak-balik lewat jaringan), hasilnya kita await sebelum dipakai.
Yang kadang terlewat: ada dua tingkat penantian. await fetch(...) hanya menunggu header respons tiba. Isi body sering belum lengkap pada saat itu — ia mengalir belakangan sebagai data stream. Karena itu membaca body juga memerlukan await, misalnya lewat response.json().
Berkas contoh berikut menyertakan server tiruan dengan dua rute: GET /produk/17 dan POST /pesanan. Kita coba keduanya satu per satu:
// fetch-dasar.mjs
// fetch GET dasar, options POST, dan jebakan body yang hanya bisa dibaca sekali.
// Jalankan di terminal: node fetch-dasar.mjs (tanpa internet).
import http from "node:http";
const server = http.createServer((req, res) => {
if (req.method === "GET" && req.url === "/produk/17") {
res.writeHead(200, { "Content-Type": "application/json" });
res.end(JSON.stringify({ id: 17, judul: "Kamus Bahasa", harga: 95000 }));
return;
}
if (req.method === "POST" && req.url === "/pesanan") {
let raw = "";
req.on("data", (potongan) => (raw += potongan));
req.on("end", () => {
const data = JSON.parse(raw);
res.writeHead(201, { "Content-Type": "application/json" });
res.end(JSON.stringify({ id: 101, total: data.item.length * data.harga }));
});
return;
}
res.writeHead(404);
res.end("tidak ditemukan");
});
server.listen(0, "127.0.0.1", async () => {
const port = server.address().port;
const dasar = `http://127.0.0.1:${port}`;
// --- 1. GET: fetch cukup diberi URL ---
const response = await fetch(`${dasar}/produk/17`);
const produk = await response.json();
console.log("GET :", response.status, "-", produk.judul, "Rp" + produk.harga);
// --- 2. POST: method, headers, dan body ditentukan lewat options ---
const responseKirim = await fetch(`${dasar}/pesanan`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ pembeli: "Budi", item: ["A", "B", "C"], harga: 15000 }),
});
const pesanan = await responseKirim.json();
console.log("POST:", responseKirim.status, "- id", pesanan.id, "total", pesanan.total);
// --- 3. body response hanya bisa dibaca sekali ---
const responseCek = await fetch(`${dasar}/produk/17`);
console.log("pertama:", await responseCek.json());
try {
await responseCek.json();
} catch (error) {
console.log("kedua :", error.name, "-", error.message);
}
server.closeAllConnections();
server.close();
});Output yang Dihasilkan:
GET : 200 - Kamus Bahasa Rp95000
POST: 201 - id 101 total 45000
pertama: { id: 17, judul: 'Kamus Bahasa', harga: 95000 }
kedua : TypeError - Body is unusable: Body has already been readMari kita telaah baris-baris pentingnya:
- Baris 8–11 (rute
GET /produk/17): server tiruan memeriksa method dan URL yang diminta, lalu menjawab200dengan headerContent-Type: application/jsondan body JSON — perilaku yang pada server nyata digantikan data dari database. - Baris 32 (
await fetch(...)): permintaanGETdikirim dengan satu argumen URL saja. Setelah baris ini selesai, header respons sudah ada di tangan, tetapi body baru tersedia setelah dibaca. - Baris 33 (
await response.json()):json()membaca seluruh body stream, menguraikan teksnya dengan parser JSON, dan mengembalikanPromiseberisi object JavaScript. Karena respons server memang JSON — tertulis pada headerContent-Type-nya — penguraian berjalan mulus. - Baris 37–41 (options): argumen kedua
fetchberupa object opsi.method: "POST"menetapkan kata kerja permintaan,headersmelampirkan header, danbodyberisi isi pesan. JSON harus diserialisasi lebih dulu denganJSON.stringify— inilah pertemuan material chapter keranjang Budi dulu dengan jaringan. - Baris 16–20 (server membaca body): body permintaan tiba bertahap; server mengumpulkannya di event
data, lalu menguraikannya di eventend. Perhatikan server membalas dengan status201 Created— kode yang memang dirancang untuk “data baru berhasil dibuat”. - Baris 48–51 (membaca body kedua kali):
responseCek.json()yang kedua ditolak denganTypeError: Body is unusable: Body has already been read. Body stream hanya mengalir satu kali; setelah habis dibaca, tidak ada yang bisa diulang dari objectResponseitu.
Options: Method, Headers, dan Body #
Object opsi pada argumen kedua fetch adalah tempat semua konfigurasi permintaan. Tiga properti yang paling sering dipakai:
method— kata kerja HTTP:"GET"(bawaan),"POST","PUT","PATCH", atau"DELETE".headers— object berisi header permintaan;Content-Type: application/jsonwajib ada bila body dikirim sebagai JSON agar server tahu cara mengurainya.body— isi pesan; string hasilJSON.stringify, atau bentuk lain sepertiURLSearchParamsuntuk data formulir.
Nilai body hanya bermakna untuk metode yang membawa data — memberikannya pada GET diabaikan. Untuk daftar opsi lain seperti mode, signal, dan cache, kita menyusurnya di chapter CORS dan AbortController.
Dua detail kecil yang menghemat waktu debug: nilai method tidak peka huruf besar-kecil ("post" sama dengan "POST"), dan object opsi yang diberikan tidak boleh dianggap resep rahasia — semua nilai di dalamnya tampil di jaringan, termasuk header yang dikirim.
Object Response: Tiga Wilayah Informasi #
Keluaran await fetch(...) bukan data mentah, melainkan object Response yang mengelompokkan tiga wilayah informasi — padanan langsung anatomi respons HTTP di chapter pembuka:
| Wilayah | Properti yang sering dipakai | Isi pada keluaran contoh |
|---|---|---|
| Status | status, statusText, ok | 201, "Created", true |
| Header | headers.get(...), headers.has(...) | "application/json" |
| Body | json(), text(), blob() | object pesanan Budi |
Kebiasaan yang sehat: baca wilayah status dan header lebih dulu, baru putuskan membaca body. Body berat yang sudah terlanjur diurai untuk respons 500 adalah pekerjaan sia-sia — dan seperti terlihat pada percobaan kedua di berkas contoh, satu Response hanya menyediakan body sekali baca.
Memilih Pembaca Body yang Tepat #
Method json() hanyalah satu dari keluarga pembaca body. Pilihannya menyesuaikan bentuk data:
response.json()— body teks JSON diuraikan menjadi nilai JavaScript; pilihan utama untuk API.response.text()— body apa pun sebagai string; cocok untuk respons HTML atau pesan teks biasa.response.blob()/response.arrayBuffer()— data biner seperti gambar atau berkas.
Ketiganya sama-sama hanya bisa dipanggil sekali per Response, dan ketiganya mengembalikan Promise. Bila format respons belum pasti, periksa dulu header Content-Type lewat response.headers.get("content-type") sebelum memilih pembaca — pola ini kita praktikkan di chapter Headers dan Content Types.
Setelah cara mengirim dan membaca respons beres, langkah berikutnya adalah memilih kata kerja yang benar untuk setiap aksi data — topik chapter Request Methods.