Halaman katalog toko Budi selama ini menampilkan daftar buku yang ditulis langsung di HTML. Setiap kali stok berubah, Budi harus membuka berkas HTML, memperbaiki angka satu per satu, lalu mengunggahnya lagi. Cara kerja itu cepat habis: data yang ia tampilkan berubah setiap hari, sementara struktur halamannya tetap. Yang dibutuhkan adalah cara bagi JavaScript untuk meminta data terbaru dari server, mengambil jawabannya, lalu menampilkannya — tanpa memuat ulang halaman.

Jalur standarnya adalah Fetch API: satu function, fetch(), yang mengirim permintaan HTTP dan mengembalikan jawaban sebagai object Response. Chapter ini membahas bentuk dasar permintaan GET, properti response.ok, pembacaan body lewat response.json(), serta urutan promise yang mendasari keduanya. Detail lebih dalam tentang status, header, method lain, dan CORS kita lanjutkan di section Network dan API.

Bentuk Dasar Permintaan GET #

Aturannya satu baris: fetch(url) menerima URL sebagai string dan segera mengembalikan sebuah promise. Ketika promise tersebut terpenuhi, nilai yang dihasilkan adalah object Response — laporan lengkap jawaban server, mulai dari status code hingga isi body. Karena fetch asinkron, kita menunggunya dengan await di dalam async function:

js
// pola dasar di halaman browser
const respons = await fetch("https://toko.example/api/buku");
const daftarBuku = await respons.json();

Di balik layar, browser melakukan beberapa langkah untuk kita: membangun permintaan HTTP GET ke URL tersebut, menunggu server menjawab, lalu mengisi promise dengan object Response yang membungkus jawabannya. Tidak ada lagi objek XMLHttpRequest dengan callback ganda seperti pada pola lama — fetch berdiri di atas promise, sehingga bisa dirangkai dengan await dan try-catch seperti pekerjaan asinkron lain yang sudah kita pelajari di section Asynchronous JavaScript.

Satu hal penting perlu ditetapkan sejak awal: promise dari fetch() selesai ketika header jawaban tiba, bukan ketika seluruh body selesai diunduh. Body bisa besar dan butuh waktu tambahan, jadi ia dibaca lewat method terpisah seperti json() yang mengembalikan promise kedua. Urutan dua promise inilah yang kita buktikan berikutnya.

Membaca Response dalam Dua Tahap Promise #

Berkas berikut memperlihatkan pola pembacaan Response dari tahap header sampai tahap body, lengkap dengan penanganan status galat. Agar contohnya bisa diuji tanpa jaringan, Response dibuat manual dengan new Response(...) — properti dan method-nya sama persis dengan object yang dikembalikan fetch():

// baca-response.js — pola membaca Response hasil fetch dalam dua tahap promise.
// Response di sini dibuat manual supaya contoh bisa diuji tanpa jaringan;
// properti dan method-nya sama persis dengan object yang dikembalikan fetch().

function bacaKatalog(respons) {
  if (!respons.ok) {
    throw new Error(`Permintaan gagal: status ${respons.status}`);
  }
  return respons.json();
}

async function utama() {
  // --- 1. response sukses: header tiba dulu, body dibaca kemudian ---
  const responsOK = new Response(
    JSON.stringify([
      { judul: "Kamus Mini Bahasa", stok: 4 },
      { judul: "Cerita di Sekitar Kita", stok: 7 },
    ]),
    { status: 200, headers: { "Content-Type": "application/json" } }
  );

  console.log("Header tiba: status", responsOK.status, "| ok:", responsOK.ok);

  const daftarBuku = await responsOK.json();
  console.log("Body dibaca:", daftarBuku.length, "judul buku");
  for (const buku of daftarBuku) {
    console.log(`- ${buku.judul} (stok ${buku.stok})`);
  }

  // --- 2. response galat HTTP: fetch tidak reject, kita yang memeriksa ---
  const respons404 = new Response("Halaman tidak ditemukan", { status: 404 });
  console.log("Header 404 tiba: status", respons404.status, "| ok:", respons404.ok);
  try {
    await bacaKatalog(respons404);
  } catch (error) {
    console.log("Tertangkap:", error.message);
  }
}

utama();

Berkas ini dijalankan langsung dengan node baca-response.js pada Node v24.21.0 — Node menyediakan global Response yang mengikuti spesifikasi yang sama dengan browser:

Output yang Dihasilkan:

text
Header tiba: status 200 | ok: true
Body dibaca: 2 judul buku
- Kamus Mini Bahasa (stok 4)
- Cerita di Sekitar Kita (stok 7)
Header 404 tiba: status 404 | ok: false
Tertangkap: Permintaan gagal: status 404

Mari kita telaah baris-baris pentingnya:

  1. Baris 5–10 (function bacaKatalog): function pembungkus yang menjadi pola baca standar. Properti respons.ok bernilai true hanya untuk status 200–299; bila bukan, kita melempar Error agar pemeriksaan status tidak boleh terlewat.
  2. Baris 14–20 (new Response(...)): object Response tiruan berisi body JSON dan status 200. Pada halaman nyata, object dengan bentuk yang sama dihasilkan oleh fetch() — kita tidak pernah membangunnya sendiri di production.
  3. Baris 22 (console.log("Header tiba: ...")): status dan ok sudah bisa dibaca seketika. Inilah tahap pertama: header tiba lebih dulu, sebelum body selesai diunduh.
  4. Baris 24 (await responsOK.json()): tahap kedua. json() membaca seluruh body lalu menguraikannya menjadi nilai JavaScript; method ini mengembalikan promise, karena pembacaan body bisa memakan waktu.
  5. Baris 31–32 (new Response(..., { status: 404 })): response kedua meniru halaman yang tidak ditemukan. ok menjadi false, tetapi promise fetch() — bila ini berasal dari jaringan sungguhan — tetap terpenuhi.
  6. Baris 33–37 (try-catch): bacaKatalog melempar Error berisi status 404, dan blok catch menangkapnya. Dengan pola ini, semua jalur gagal (status galat maupun kegagalan jaringan) bermuara di satu tempat.

Pola Lengkap di Halaman Browser #

Dengan kedua tahap tadi, pola yang kita tulis di halaman katalog Budi menjadi seperti berikut. Cuplikan ini memanggil server sungguhan, sehingga kita sajikan sebagai pola — bukan berkas yang dijalankan di terminal:

js Pola: memuat katalog dari server
async function muatKatalog() {
  try {
    const respons = await fetch("https://toko.example/api/buku");
    if (!respons.ok) {
      console.log("Server menjawab dengan status:", respons.status);
      return;
    }
    const daftarBuku = await respons.json();
    for (const buku of daftarBuku) {
      console.log(`${buku.judul}: stok ${buku.stok}`);
    }
  } catch (error) {
    console.log("Jaringan bermasalah:", error.message);
  }
}

muatKatalog();

Keluaran console browser:

text
Kamus Mini Bahasa: stok 4
Cerita di Sekitar Kita: stok 7

Keluaran di atas adalah ilustrasi untuk skenario server menjawab 200 dengan data katalog — bukan hasil eksekusi terminal, karena fetch() memang membutuhkan jaringan dan halaman browser. Urutan kerjanya tetap yang sudah kita buktikan di berkas sebelumnya: await fetch(...) selesai saat header tiba, response.ok menentukan jalur sukses, lalu await response.json() mengirim promise kedua yang berisi data siap pakai.

Konsep yang sama — permintaan, status, header, dan method selain GET — kita kembangkan bertahap di section Network dan API. Untuk sekarang, pola fetch → cek ok → json() sudah cukup untuk membawa data nyata ke halaman kita.

Berkas Sumber

Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.

baca-response.js

Unduh berkas
javascript
// baca-response.js — pola membaca Response hasil fetch dalam dua tahap promise.
// Response di sini dibuat manual supaya contoh bisa diuji tanpa jaringan;
// properti dan method-nya sama persis dengan object yang dikembalikan fetch().

function bacaKatalog(respons) {
  if (!respons.ok) {
    throw new Error(`Permintaan gagal: status ${respons.status}`);
  }
  return respons.json();
}

async function utama() {
  // --- 1. response sukses: header tiba dulu, body dibaca kemudian ---
  const responsOK = new Response(
    JSON.stringify([
      { judul: "Kamus Mini Bahasa", stok: 4 },
      { judul: "Cerita di Sekitar Kita", stok: 7 },
    ]),
    { status: 200, headers: { "Content-Type": "application/json" } }
  );

  console.log("Header tiba: status", responsOK.status, "| ok:", responsOK.ok);

  const daftarBuku = await responsOK.json();
  console.log("Body dibaca:", daftarBuku.length, "judul buku");
  for (const buku of daftarBuku) {
    console.log(`- ${buku.judul} (stok ${buku.stok})`);
  }

  // --- 2. response galat HTTP: fetch tidak reject, kita yang memeriksa ---
  const respons404 = new Response("Halaman tidak ditemukan", { status: 404 });
  console.log("Header 404 tiba: status", respons404.status, "| ok:", respons404.ok);
  try {
    await bacaKatalog(respons404);
  } catch (error) {
    console.log("Tertangkap:", error.message);
  }
}

utama();