Javascript Fetch API Async Data Flow JSON Parsing Error Handling
Definisi
Fetch API adalah API bawaan JavaScript untuk melakukan request ke server, biasanya untuk mengambil data atau mengirim data lewat HTTP. Di browser modern, fetch() sudah tersedia tanpa library tambahan.
Di praktik harian, fetch dipakai untuk:
- mengambil data dari endpoint REST atau JSON API
- mengirim form data atau payload JSON ke server
- memuat data secara bertahap setelah halaman tampil
- menyelaraskan state UI dengan data terbaru dari backend
- mengganti
XMLHttpRequestdi kebanyakan kasus modern
Kalau alurnya sederhana dan targetnya browser modern, fetch biasanya jadi pilihan default. Kalau butuh fitur yang sangat spesifik seperti progress upload/download yang detail, timeout bawaan yang eksplisit, atau interceptors tingkat library, kadang developer memilih wrapper seperti Axios. Tapi untuk sebagian besar kebutuhan dasar, fetch sudah cukup dan lebih ringan karena native.
Kapan memakai Fetch API
Pakai fetch saat kamu perlu kerja HTTP dari JavaScript, misalnya:
- load data saat halaman dibuka
- reload data setelah user submit form
- cari data secara dinamis saat user mengetik
- sinkronisasi state lokal dengan server
- memanggil endpoint publik atau private yang mengembalikan JSON
Jangan pakai fetch hanya untuk “semua request” tanpa berpikir. Pertimbangkan hal ini:
- Butuh JSON sederhana?
fetchcocok. - Butuh kontrol penuh atas request/response?
fetchtetap cocok, asal kamu siap menulis handling sendiri. - Butuh kenyamanan wrapper dan interceptor? library bisa lebih praktis.
- Butuh akses di lingkungan non-browser? pastikan runtime mendukung
fetchatau sediakan polyfill.
Prinsipnya: fetch bagus ketika kamu ingin alur request yang eksplisit dan mudah dibaca.
Cara kerja request dan response
fetch() mengirim request dan mengembalikan Promise. Artinya, hasilnya tidak langsung tersedia di baris yang sama.
Urutan dasarnya begini:
- JavaScript memanggil
fetch(url, options). - Browser membangun request HTTP.
- Request dikirim ke server.
- Server mengembalikan response.
- Promise resolved ke objek
Response. - Data response diproses lagi, misalnya dengan
.json(). - Hasil parse dipakai untuk update state atau UI.
Yang sering bikin bingung: fetch hanya gagal otomatis kalau ada error network level, misalnya koneksi putus atau request diblokir total. Kalau server membalas 404, 500, atau response error lain, Promise-nya tetap resolved. Karena itu kita harus cek response.ok sendiri.
Alur async data flow
Kalau dipetakan ke UI, flow yang sehat biasanya seperti ini:
Diagram ini penting karena menunjukkan bahwa request sukses belum tentu berarti data bisa langsung dipakai. Ada beberapa lapisan yang bisa gagal:
- request network gagal
- server merespons dengan status error
- body tidak berisi JSON valid
- data JSON valid tapi strukturnya tidak sesuai yang diharapkan UI
Contoh dasar fetch
async function loadUsers() {
const response = await fetch('/api/users');
const users = await response.json();
return users;
}Contoh di atas terlihat pendek, tapi masih belum aman sepenuhnya. Kalau server mengembalikan status error, response.json() tetap bisa dipanggil dan kamu bisa saja membaca body error sebagai data sukses. Jadi pola yang lebih sehat biasanya menambahkan pengecekan status.
Pola yang lebih aman
async function loadUsers() {
const response = await fetch('/api/users');
if (!response.ok) {
throw new Error(`Request gagal: ${response.status} ${response.statusText}`);
}
const users = await response.json();
return users;
}Kenapa response.ok penting:
response.okbernilaitruehanya untuk status 2xx- status 404, 401, 403, 500, dan sejenisnya tidak dianggap sukses
- tanpa cek ini, UI bisa mengira request berhasil padahal backend sedang menolak request
Kalau ingin lebih jelas, kamu bisa memetakan status tertentu:
async function loadUsers() {
const response = await fetch('/api/users');
if (response.status === 401) {
throw new Error('Sesi habis, silakan login lagi');
}
if (!response.ok) {
throw new Error('Gagal mengambil data users');
}
return response.json();
}JSON parsing
Kalau response body berisi JSON, gunakan response.json() untuk mengubah string body menjadi object JavaScript. Method ini juga async, jadi hasilnya perlu di-await.
const response = await fetch('/api/profile');
const data = await response.json();Hal yang perlu diingat:
response.json()hanya cocok kalau body memang JSON- kalau body kosong, parsing bisa gagal
- kalau server mengirim text/HTML tapi kamu memaksa
json(), akan muncul error parsing - kalau header atau konten response tidak sesuai, data bisa gagal dibaca dengan benar
Kalau kamu ingin debugging, kadang berguna membaca body sebagai text lebih dulu:
const response = await fetch('/api/profile');
const raw = await response.text();
console.log(raw);Itu membantu saat kamu curiga server sebenarnya mengirim HTML error page, bukan JSON.
Contoh error handling dasar
async function loadProfile() {
try {
const response = await fetch('/api/profile');
if (!response.ok) {
throw new Error(`Gagal load profile: ${response.status}`);
}
const profile = await response.json();
return profile;
} catch (error) {
console.error('Load profile gagal', error);
throw error;
}
}Pola ini memisahkan dua jenis kegagalan:
- error network / runtime:
fetch()melempar atau Promise gagal - error HTTP: response datang, tapi status bukan sukses
- error parsing: response ada, tapi JSON tidak valid
Di UI, biasanya error itu diterjemahkan jadi fallback state, misalnya:
loadingdataerror
Contohnya:
const state = {
loading: false,
data: null,
error: null,
};
async function refreshUsers() {
state.loading = true;
state.error = null;
try {
const response = await fetch('/api/users');
if (!response.ok) {
throw new Error('Gagal memuat users');
}
state.data = await response.json();
} catch (error) {
state.error = error.message;
} finally {
state.loading = false;
}
}Jebakan umum saat pakai fetch
1) Lupa cek response.ok
Ini salah satu jebakan paling umum. Tanpa cek status, response error bisa diproses seperti data normal.
Contoh yang berbahaya:
const response = await fetch('/api/users');
const data = await response.json();Kalau endpoint mengembalikan 404 dengan body JSON error, kode di atas tetap berhasil parse body, padahal isinya bukan data yang diharapkan.
2) Mengira semua gagal akan masuk catch
Tidak semua response error akan masuk catch. Status 404 atau 500 tidak otomatis melempar exception di fetch. Kamu harus menanganinya manual.
3) CORS
Saat frontend dan backend berbeda origin, browser bisa memblokir request karena aturan CORS. Ini bukan bug JavaScript biasa, tapi mekanisme keamanan browser.
Gejala umum CORS:
- request terlihat “gagal” di browser
- console menampilkan error terkait CORS
- server mungkin sebenarnya sudah membalas, tapi browser menolak akses ke response-nya
Solusinya ada di server, bukan di fetch-nya. Server perlu mengirim header CORS yang benar dan, jika perlu, menangani preflight request OPTIONS.
4) Parsing JSON gagal
response.json() akan gagal kalau body bukan JSON valid. Ini sering terjadi saat:
- server mengembalikan HTML error page
- response kosong
- response dipotong atau rusak
- content type tidak cocok dengan isi body
Kalau parsing gagal, tangani seperti error data, bukan cuma error network.
5) Body dipakai dua kali
Body response bersifat sekali baca. Kalau sudah dipakai oleh response.json(), kamu tidak bisa membacanya lagi sebagai text kecuali kamu clone response dulu.
const response = await fetch('/api/users');
const data = await response.json();
// response.text() di bawah ini sudah terlambat6) State di-update sebelum data valid
Kadang developer langsung menaruh hasil fetch ke state sebelum memvalidasi bentuk datanya. Akibatnya UI bisa crash saat data tidak sesuai struktur.
Lebih aman kalau kamu cek shape minimal dulu:
const data = await response.json();
if (!Array.isArray(data)) {
throw new Error('Format data users tidak sesuai');
}Catatan implementasi yang sehat
- selalu bedakan
loading,success, danerror - cek
response.oksebelum parse body sebagai data utama - perlakukan parsing JSON sebagai langkah yang bisa gagal
- simpan pesan error yang cukup jelas untuk debugging
- jangan langsung percaya bentuk data dari server
- kalau endpoint lintas origin gagal, cek CORS di server lebih dulu
Kalau request dipakai di komponen UI, alurnya biasanya:
- event atau lifecycle memicu request
- state
loadingdiaktifkan - request dikirim
- response dicek statusnya
- body diparse
- data divalidasi ringan
- state
datadiisi - state
loadingdimatikan - jika gagal, state
errordiisi
Contoh end-to-end
async function loadProducts() {
try {
const response = await fetch('/api/products');
if (!response.ok) {
throw new Error(`Request products gagal: ${response.status}`);
}
const products = await response.json();
if (!Array.isArray(products)) {
throw new Error('Format products tidak valid');
}
return products;
} catch (error) {
console.error('loadProducts error:', error);
return [];
}
}Pola ini masih sederhana, tapi sudah cukup rapi untuk debugging harian karena:
- request dan parsing dipisah jelas
- error HTTP tidak disamakan dengan success
- struktur data divalidasi minimal
- caller tetap mendapat hasil yang terkontrol
Ringkasan praktis
Pakai fetch kalau kamu butuh request HTTP yang ringan, native, dan cukup fleksibel untuk kerja data modern di browser. Setelah request dikirim, ingat bahwa alurnya tidak selesai saat Promise resolved. Kamu masih perlu:
- cek
response.ok - parse body dengan benar
- handle JSON parsing gagal
- waspada CORS saat origin berbeda
- update state hanya setelah data valid
Kalau alurnya dipahami dengan benar, debugging fetch jadi jauh lebih tenang: bukan lagi “kenapa request ini aneh?”, tapi “gagalnya ada di layer yang mana?”.