Belajar Nuxt - API Integration & Data Protection
Series/Belajar Nuxt/Episode 13
Episode 13 of 24

Belajar Nuxt - API Integration & Data Protection

Episode ini membahas integrasi API eksternal di Nuxt: memanggil layanan pihak ketiga dari server, melindungi request dengan auth headers, menyimpan secret dengan aman lewat runtime config, serta menerapkan rate limiting dan error handling yang tangguh.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Pendahuluan

Aplikasi nyata jarang bekerja sendiri — dia memanggil payment gateway, layanan email, atau API cuaca. Episode 13 membahas cara mengintegrasikan API eksternal dengan benar di Nuxt: dari mana harus memanggil, bagaimana request diamankan, di mana secret disimpan, dan bagaimana menangani kegagalan.

Aturan terpenting episode ini: panggilan API eksternal yang membutuhkan secret harus dilakukan di server, bukan di browser. Kode client bisa dibaca siapa saja, jadi api key dan token hanya boleh hidup di sisi server.

Menggunakan API Eksternal di Nuxt

Memanggil dari Server Routes

Tempat paling tepat untuk panggilan eksternal adalah server/api. Mari buat endpoint yang menghubungkan ke payment gateway:

JSserver/api/pembayaran/index.ts
export default defineEventHandler(async (event) => {
  const body = await readBody(event)
 
  const hasil = await $fetch("https://api.payment.dev/v1/charge", {
    method: "POST",
    body,
    headers: {
      Authorization: `Bearer ${useRuntimeConfig().apiKeyPembayaran}`,
    },
  })
 
  return hasil
})

$fetch di server route membawa Authorization header yang diambil dari runtime config. Browser tidak pernah melihat api key ini karena seluruh panggilan terjadi di server.

Proksi untuk Masalah CORS

Sering kali masalahnya bukan keamanan, tapi CORS — browser memblokir panggilan lintas origin. Memakai server route sebagai proksi menyelesaikan dua masalah sekaligus: CORS dan perlindungan secret.

Protecting API Requests dan Auth Headers

Selalu Sertakan Token

Setiap request ke API eksternal yang butuh otorisasi wajib membawa token. Simpan token di runtime config dan jangan pernah hardcode:

JSRequest dengan auth header
export default defineEventHandler(async (event) => {
  const config = useRuntimeConfig()
 
  const res = await $fetch("https://api.eksternal.dev/v2/produk", {
    headers: {
      "X-Api-Key": config.apiKeyEksternal,
    },
  })
 
  return res
})

config.apiKeyEksternal dibaca dari NUXT_API_KEY_EKSTERNAL di environment. Header kustom seperti X-Api-Key adalah pola umum yang dipakai banyak API pihak ketiga.

Endpoint yang Tidak Perlu Token

Sebagian API publik memang tidak butuh token, tapi tetap batasi pemanggilannya. Jika API lain berbayar atau punya kuota, jangan membiarkan siapa pun memanggilnya tanpa kendali.

Securely Handling Sensitive Data and Secrets

Secret Hanya di Sisi Server

Klasifikasi data itu krusial. Yang boleh di runtimeConfig.public hanya data publik seperti base URL. Api key, token, dan password hanya di runtimeConfig private:

JSMemisahkan secret
export default defineNuxtConfig({
  runtimeConfig: {
    stripeSecret: process.env.STRIPE_SECRET_KEY,
    public: {
      stripePublishable: process.env.STRIPE_PUBLISHABLE_KEY,
    },
  },
})

stripeSecret tidak pernah dikirim ke client, sedangkan stripePublishable aman dipakai di frontend — misalnya untuk menampilkan form kartu.

Jangan Log Secret

Kesalahan umum: console.log(config.stripeSecret) saat debugging, lalu bocor ke log server yang bisa dibaca orang lain. Buat aturan sederhana: jangan pernah menampilkan secret di log, error message, atau response API.

Rate Limiting

Melindungi Endpoint dari Penyalahgunaan

Rate limiting membatasi jumlah request per pengguna. Nitro menyediakan storage yang cocok untuk pola ini:

JSRate limiting berbasis IP
export default defineEventHandler(async (event) => {
  const ip = getRequestIP(event, { xForwardedFor: true })
  const kunci = `rate:${ip}`
  const storage = useStorage("cache")
  const jumlah = (await storage.getItem(kunci)) || 0
 
  if (jumlah >= 100) {
    throw createError({
      statusCode: 429,
      message: "Terlalu banyak request",
    })
  }
 
  await storage.setItem(kunci, jumlah + 1, { ttl: 3600 })
  return { ok: true }
})

Pola di atas menghitung request per IP memakai storage Nitro dengan TTL satu jam. Status 429 dikembalikan saat batas terlampaui — melindungi endpoint dari brute force dan penyalahgunaan.

Batas yang Wajar

Sesuaikan batas dengan sifat endpoint: halaman publik bisa lebih longgar, endpoint login sebaiknya ketat. Kombinasikan dengan backoff eksponensial di sisi client untuk pengalaman yang tetap baik.

Error Handling

Menangkap Kegagalan Eksternal

API pihak ketiga bisa gagal, lambat, atau mengubah format. Server route wajib menangkap error dan mengembalikan pesan yang jelas:

JSMenangkap error eksternal
export default defineEventHandler(async () => {
  try {
    const res = await $fetch("https://api.eksternal.dev/v1/status")
    return res
  } catch (e) {
    throw createError({
      statusCode: 503,
      message: "Layanan eksternal sedang tidak tersedia",
    })
  }
})

createError({ statusCode: 503, ... }) menyampaikan kegagalan ke client dengan status yang tepat. Jangan pernah membocorkan detail internal seperti stack trace ke pengguna.

Retry dengan Batasan

Untuk kegagalan yang bersifat sementara, tambahkan retry dengan jeda yang meningkat:

JSRetry dengan jeda meningkat
for (let i = 1; i <= 3; i++) {
  try {
    return await $fetch("https://api.eksternal.dev/v1/resi")
  } catch (e) {
    if (i === 3) throw e
    await new Promise((r) => setTimeout(r, i * 500))
  }
}

Pola retry di atas mencoba hingga tiga kali dengan jeda bertingkat. Kombinasikan dengan timeout agar request yang menggantung tidak menghabiskan resource server.

Penutup

Episode 13 mengamankan integrasi eksternal kalian: panggilan API pihak ketiga dilakukan dari server, request dilindungi auth headers, secret disimpan hanya di sisi server lewat runtime config, rate limiting melindungi endpoint dari penyalahgunaan, dan error handling membuat sistem tangguh terhadap kegagalan.

Inti yang harus dibawa pulang:

  • Panggil API eksternal dari server routes, bukan dari browser.
  • Server route sebagai proksi menyelesaikan CORS sekaligus melindungi secret.
  • Api key dan token hanya di runtimeConfig private, tidak pernah di public.
  • Jangan menampilkan secret di log, error, atau response.
  • Rate limiting memakai storage Nitro untuk melindungi endpoint.
  • Tangkap error eksternal dan kembalikan pesan yang jelas tanpa detail internal.

Di episode 14 selanjutnya kita akan membahas caching dan performance — caching data dengan Nitro dan browser cache, static generation dan ISR, optimasi page load dan pengiriman aset, serta pemantauan build performance. Toko kalian mulai berlari kencang.

Belajar Nuxt - API Integration & Data Protection | Belajar Nuxt