Soal 1Setelah const response = await fetch(url); dijalankan, apa isi response?
fetch — Mengambil Data dari API
Membahas fetch dan json() untuk mengambil JSON dari URL, response.ok untuk mendeteksi kegagalan, URL relatif, dan memuat dua file sekaligus dengan Promise.all.
Sejauh ini, data di latihan selalu ditulis langsung di dalam kode. Di situs sungguhan, harga dan stok bisa berubah, jadi setiap kali dibuka, halaman meminta data ke API milik server (URL yang dipakai program untuk mengambil data).
Artikel ini membahas fetch untuk mengambil data dari sebuah URL, dan response.ok untuk mengecek apakah request-nya berhasil.
Mengambil JSON dari API — fetch dan json()
Anggap kamu ingin halaman riwayat order menampilkan daftar order yang tersimpan di server. Order itu datang sebagai string JSON, jadi kamu perlu cara untuk menunggu sampai datanya tiba, lalu langkah untuk mengubah string itu kembali menjadi array. Di latihan, kamu akan mengambil file JSON dari folder fixtures di situs ini sebagai pengganti API sungguhan.
fetch (function yang meminta data di sebuah URL ke server) mengembalikan Promise yang fulfilled dengan Response, yaitu object yang mewakili jawaban server. status (angka yang bernilai 200 kalau berhasil) dan header (informasi tentang response yang dikirim sebelum body) datang lebih dulu, lalu body menyusul, jadi kamu perlu await sekali lagi pada response.json() untuk mendapatkan body-nya.
// Ambil JSON order yang disimpan di situs ini (cara menulis URL dibahas di bagian berikutnya)
const response = await fetch("fixtures/id/orders.json");
console.log(response.status); // 200
// Baca seluruh body dan ubah dari JSON menjadi array
const orders = await response.json();
console.log(orders.length); // 3
console.log(orders[1].total); // 12600
// Setelah ini, orders adalah array biasa
const preparing = orders.filter((order) => order.status === "Diproses");
console.log(preparing.map((order) => order.id).join(", ")); // A-3002, A-3003
json() membaca body sampai habis dan mengubahnya dengan cara yang sama seperti JSON.parse sebelum mengembalikan hasilnya, jadi hasil itu kamu tunggu dengan await. Setelah diubah, orders adalah array biasa, jadi filter dan map bisa langsung dipakai.
Response yang Di-log Tampil sebagai {}
Di console latihan, console.log(response) menampilkan {}, sama seperti element DOM. response.json() tanpa await adalah Promise, jadi hasilnya juga {}. Untuk mengecek Response, tampilkan status-nya; untuk mengecek body, tampilkan value yang kamu dapat dari await pada json().
Menulis URL Berdasarkan Lokasi Halaman — URL Relatif
Di bagian sebelumnya, cukup menulis "fixtures/id/orders.json" untuk mengambil file-nya. URL lengkap yang diawali https:// ikut memuat domain (bagian setelah https://, seperti runner.desktechlearn.com, yang menunjukkan situsnya), jadi URL itu harus kamu ubah setiap kali situsnya pindah.
URL relatif (URL yang ditulis berdasarkan URL halaman yang sedang dibuka) dicari mulai dari folder halaman itu kalau tidak diawali /, dan mulai dari root situs kalau diawali /. Kode latihan tidak berjalan di halaman artikel, tapi di runner.html, halaman tersembunyi di runner.desktechlearn.com.
// URL halaman tempat kode ini berjalan (console latihan)
// https://runner.desktechlearn.com/tools/js-editor/runner.html
// Tanpa / di depan: dicari mulai dari js-editor, folder tempat runner.html berada
const fromPage = await fetch("fixtures/id/orders.json");
console.log(fromPage.url); // url adalah URL yang benar-benar diminta
// https://runner.desktechlearn.com/tools/js-editor/fixtures/id/orders.json
// Dengan / di depan: dicari mulai dari root situs
const fromRoot = await fetch("/tools/js-editor/fixtures/id/orders.json");
console.log(fromRoot.url === fromPage.url); // true (keduanya menunjuk file yang sama)
// Kalau fixtures/id/ tidak ditulis, file dicari langsung di dalam js-editor
const noFolder = await fetch("orders.json");
console.log(noFolder.url);
// https://runner.desktechlearn.com/tools/js-editor/orders.json
- URL yang diawali
/mulai dari sini
runner.html— halaman tempat kode latihan berjalan- URL tanpa
/di depan mulai dari sini
- Berisi
orders.json,users.json, danproducts.json
URL yang diawali / selalu menunjuk file yang sama, di folder mana pun halamannya berada. URL tanpa / tetap berfungsi kalau halaman dan fixtures dipindahkan bersama ke folder lain. Tabel di bawah menunjukkan titik awal tiap URL dan apakah file-nya ditemukan.
| URL | Titik awal | File ditemukan? |
|---|---|---|
| fixtures/id/orders.json | js-editor | Ya |
| /tools/js-editor/fixtures/id/orders.json | Root situs | Ya (file yang sama) |
| orders.json | js-editor | Tidak (tidak ada di js-editor) |
Di DevTools, URL Dihitung dari Halaman Artikel
Kalau kamu membuka Console DevTools di halaman artikel lalu menjalankan fetch("fixtures/id/orders.json"), titik awalnya adalah URL halaman artikel, jadi request-nya tidak pernah sampai ke fixtures. Server halaman artikel mengembalikan HTML halaman dengan status 200 bahkan untuk path yang tidak ada, jadi fetch-nya bisa terlihat berhasil, padahal yang kamu terima bukan JSON.
Mendeteksi Request yang Gagal — response.ok dan status
Kalau URL-nya salah ketik atau file-nya sudah dihapus, server menjawab bahwa file itu tidak ditemukan. Jawabannya tetap datang, jadi fetch tetap fulfilled dengan Response. Walaupun ada di dalam try / catch, eksekusi tidak pindah ke catch, melainkan lanjut ke baris berikutnya yang membaca body.
response.ok bernilai true kalau status ada di antara 200 dan 299. Kode sukses bukan hanya 200 (201 juga termasuk), jadi pakai ok untuk menentukan apakah request-nya berhasil. Biasanya server mengembalikan 404 (Not Found) untuk file yang tidak ada, tapi server console latihan mengembalikan 403 (Forbidden).
// URL dengan salah ketik: orders ditulis order
const response = await fetch("fixtures/id/order.json");
// Walaupun file-nya tidak ditemukan, fetch tetap fulfilled dan mengembalikan Response
console.log(response.ok); // false
console.log(response.status); // 404 atau 403 (tergantung server; console latihan mengembalikan 403)
// Ubah body menjadi array hanya kalau ok bernilai true
if (response.ok) {
const orders = await response.json();
console.log(`Jumlah order: ${orders.length}`);
} else {
console.log("Gagal memuat daftar order"); // Gagal memuat daftar order
}
Di kolom kanan, body-nya berisi penjelasan error, bukan JSON (di console latihan bentuknya XML), jadi json() melempar SyntaxError di baris itu. Kolom tengah mengecek ok lebih dulu dan menampilkan pesan tanpa membaca body, jadi request yang gagal berakhir dengan pesan di layar, bukan error.
Mengambil Dua File Sekaligus — async function dan Promise.all
Halaman admin yang menampilkan jumlah member dan jumlah order berdampingan butuh dua file JSON. Keduanya tidak saling bergantung, jadi kamu memuatnya secara paralel (memulai beberapa proses sekaligus, lalu menunggu semuanya), seperti di artikel async / await. Tapi kalau kamu memanggil fetch dua kali lalu memberikan hasilnya ke Promise.all, yang kamu dapat adalah dua Response, bukan body-nya.
Kalau semua langkah dari fetch sampai json() kamu bungkus dalam satu async function, Promise yang dikembalikan saat function itu dipanggil akan fulfilled dengan isi body-nya. Kalau function itu dipanggil dua kali lalu ditunggu dengan Promise.all, kamu mendapat array berisi isi body sesuai urutan yang kamu berikan.
// Bungkus fetch sampai json() dan kembalikan isi body-nya (null kalau tidak ditemukan)
async function loadJson(path) {
const response = await fetch(path);
if (!response.ok) {
return null;
}
return await response.json();
}
// Kalau yang diberikan 2 panggilan fetch, hasilnya Response
const responses = await Promise.all([
fetch("fixtures/id/products.json"),
fetch("fixtures/id/orders.json"),
]);
console.log(responses[0].length); // undefined (bukan array)
// Memanggil loadJson 2 kali memulai keduanya sekaligus, dan Promise.all mengumpulkan array body-nya
const [products, orders] = await Promise.all([
loadJson("fixtures/id/products.json"),
loadJson("fixtures/id/orders.json"),
]);
console.log(`${products.length} produk / ${orders.length} order`); // 4 produk / 3 order
Kalau satu saja Promise yang kamu berikan rejected, Promise.all gagal tanpa memberikan hasil lainnya. loadJson fulfilled dengan null saat ok bernilai false, jadi walaupun satu file tidak ada, kamu tetap mendapat array yang lain.
Cek Pemahaman
Jawab setiap pertanyaan satu per satu.
Soal 2Dengan path yang tidak ada, bagaimana kondisinya tepat setelah const res = await fetch(url); dijalankan?
Soal 3Di kode yang berjalan di /tools/js-editor/runner.html, di mana fetch("users.json") mencari file-nya?