Episode ini membahas integrasi data eksternal: mengambil API di loader dan action, bekerja dengan backend REST dan GraphQL, penanganan auth token dan request aman, serta rate limiting dan error fallback yang baik.

Aplikasi nyata jarang hidup sendiri. Pencarian memakai layanan eksternal, pembayaran memakai provider pihak ketiga, dan rekomendasi datang dari model AI. Episode 13 membahas cara Remix berkomunikasi dengan dunia luar secara aman dan efisien.
Keuntungan terbesar: karena loader dan action berjalan di server, panggilan API eksternal tidak terlihat di client. Token dan key tersembunyi, CORS tidak menjadi masalah, dan data bisa diolah sebelum dikirim ke browser. Ini alasan lain pola server-first Remix sangat praktis.
Episode 13 akan membahas fetching di loader dan action, integrasi REST dan GraphQL, penanganan token, serta rate limiting dan fallback error.
Loader bisa memanggil API eksternal dengan fetch, mengolah respons, lalu mengirimkan hasil yang sudah bersih ke komponen:
export async function loader() {
const res = await fetch("https://api.contoh.dev/posts", {
headers: { Authorization: `Bearer ${process.env.API_TOKEN}` },
});
if (!res.ok) {
throw new Response("Gagal memuat data", { status: 502 });
}
const posts = await res.json();
return { posts };
}Token tidak pernah terlihat oleh client karena fetch terjadi di server. CORS tidak relevan di sini — kalian bebas memanggil domain mana pun dari server.
Loader menerima request yang URL-nya bisa dibaca untuk parameter halaman, pencarian, atau filter. new URL(request.url) memberi akses ke searchParams, yang kemudian diteruskan ke API eksternal. Pola ini menjaga satu sumber kebenaran: URL.
API REST umumnya mengembalikan lebih banyak data dari yang dibutuhkan. Transformasi di loader — memilih field, mengganti nama, menambahkan data pelengkap — menjaga komponen tetap sederhana dan payload client sekecil mungkin.
export async function loader() {
const res = await fetch("https://api.contoh.dev/posts?limit=10");
const data = await res.json();
const ringkas = data.posts.map((p) => ({
id: p.id,
judul: p.title,
penulis: p.author.username,
}));
return { posts: ringkas };
}Transformasi di loader berarti client tidak perlu menulis ulang data mentah. Struktur yang dikirim ke browser sesuai kebutuhan UI, bukan sesuai kebutuhan API.
GraphQL memungkinkan meminta tepat field yang dibutuhkan dalam satu request. Di loader, cukup kirim query dan token:
export async function loader() {
const query = "{ posts { id title } }";
const res = await fetch("https://api.contoh.dev/graphql", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.GRAPHQL_TOKEN}`,
},
body: JSON.stringify({ query }),
});
return { posts: (await res.json()).data.posts };
}GraphQL mengurangi over-fetching, tapi tetap jalankan di server agar token aman. Untuk query kompleks, library seperti urql atau Apollo bisa dipakai, tapi fetch polos sering cukup untuk kebutuhan route.
Auth token external disimpan di environment variables dan hanya dibaca di loader serta action. Jangan pernah mengeksposnya ke client. Bila token perlu digunakan di client untuk alasan tertentu, buat resource route yang bertindak sebagai proxy — client memanggil endpoint kalian, bukan API eksternal.
Request eksternal bisa gagal atau lambat. Tambahkan timeout dengan AbortSignal dan pertimbangkan retry untuk error sementara. Pola yang sehat: gagal cepat dengan pesan jelas daripada hang tanpa kabar.
API eksternal punya kuota. Hindari memanggil berulang untuk data yang jarang berubah dengan memanfaatkan caching dari episode 9. Pertimbangkan juga antrean untuk pekerjaan berat yang tidak harus sinkron.
Saat API eksternal down, aplikasi tidak boleh ikut down. Pola yang umum: sediakan data cadangan (misalnya versi terakhir dari database), atau tampilkan state kosong yang jelas dengan pesan yang bisa dipahami pengguna.
export async function loader() {
try {
const res = await fetch("https://api.contoh.dev/posts");
if (!res.ok) throw new Error("bad status");
return { posts: await res.json() };
} catch {
return { posts: [], sumber: "cadangan" };
}
}Try/catch di loader mengubah kegagalan eksternal menjadi respons yang terkontrol. UI tetap me-render, dan pengguna diberi tahu lewat field sumber.
Episode 13 membuat aplikasi kalian terbuka ke dunia: fetching eksternal di loader dan action, integrasi REST dan GraphQL dengan transformasi data, token yang hanya hidup di server, serta rate limiting dan fallback error yang menjaga aplikasi tetap bernapas saat layanan lain tumbang.
Inti yang harus dibawa pulang:
Di episode 14 selanjutnya kita akan membahas network performance dan caching — strategi HTTP caching untuk Remix, integrasi CDN dan edge cache, prefetching data dan links, serta optimasi first load dan navigasi berikutnya. Data luar masuk; sekarang kita pastikan perjalanannya secepat mungkin.