Nuxt.js dapat menjaga kontrak API dan autentikasi dengan memastikan setiap permintaan mengikuti dokumentasi OpenAPI atau kontrak uji yang terpublikasi, menerapkan middleware auth yang konsisten, serta pola idempoten dan retry yang aman agar client tidak mengalami behavior yang tidak terduga. Pendekatan ini memperjelas batasan error handling dan memberi kejelasan bagi tim frontend tentang respons yang bisa diandalkan.

Pembahasan berikut menjelaskan bagaimana menggabungkan dokumentasi kontrak, middleware auth, pola idempoten, strategi retry otomatis, serta validasi webhook HMAC agar integrasi dengan layanan eksternal tetap terjamin.

Menetapkan Kontrak API dan Auth di Nuxt.js

Mulai dari dokumentasi OpenAPI hingga contract test, frontend Nuxt.js membutuhkan definisi yang jelas tentang endpoint, tipe parameter, dan daftar error yang mungkin diterima. Tim backend harus mengunggah schema OpenAPI yang valid serta mendistribusikan hasil contract test (misalnya Pact atau Postman Contract Tests) sehingga Nuxt.js tahu batasan respons dan header autentikasi.

Di sisi Nuxt, gunakan tooling seperti nuxt-swagger-ui untuk memvalidasi spec secara lokal, tapi yang lebih penting adalah mengekspor informasi ke runtime: global store atau plugin dapat memuat metadata kontrak (status code daftar, body schema minimal) agar middleware auth dan error handler bisa merespons sesuai kontrak.

Contoh dokumentasi minimal dalam repository bisa berupa folder contracts/openapi.yaml plus skrip npm run validate:contract yang dijalankan di CI untuk memastikan contract tidak bergeser. Dengan begitu, pengembang Nuxt tahu bahwa respons 409 artinya konflik idempoten, 401 berarti token invalid, dan seterusnya.

Pola Idempoten dan Retry dalam Komunikasi Eksternal

Ketika Nuxt.js memanggil API eksternal seperti pembayaran atau order, dunia nyata sering mengalami timeout dan duplikasi permintaan. Penerapan header idempoten (misalnya X-Request-Id atau UUID yang sama) memungkinkan backend mengenali permintaan ulang.

Berikut contoh composable Nuxt yang menggabungkan deduplikasi retry dan header idempoten:

import { v4 as uuidv4 } from 'uuid'

export const useApiClient = () => {
  const config = useRuntimeConfig()
  const token = useCookie('auth_token')
  const pendingRequests = new Map()

  const request = async (path, options = {}) => {
    const key = `${path}:${JSON.stringify(options.body ?? {})}`
    if (pendingRequests.has(key)) {
      return pendingRequests.get(key)
    }

    const controller = new AbortController()
    const headers = {
      'Content-Type': 'application/json',
      'X-Request-Id': uuidv4(),
      Authorization: token.value ? `Bearer ${token.value}` : undefined,
      ...(options.headers ?? {})
    }

    const fetchPromise = (async () => {
      try {
        for (let attempt = 1; attempt <= 3; attempt += 1) {
          const response = await $fetch(`${config.public.apiBase}${path}`, {
            signal: controller.signal,
            ...options,
            headers,
            retry: 0 // manual retry
          })
          pendingRequests.delete(key)
          return response
        }
      } catch (error) {
        if (attempt === 3 || error.name === 'AbortError') {
          throw error
        }
        await new Promise((resolve) => setTimeout(resolve, attempt * 200))
      }
    })()

    pendingRequests.set(key, fetchPromise)
    return fetchPromise
  }

  return { request }
}

Composable ini menyimpan pendingRequests untuk deduplikasi idempoten, menambahkan header X-Request-Id, dan menyediakan retry manual dengan backoff ringan. Pendekatan seperti ini mencegah permintaan kedua tanpa menunggu timeout provider, serta memitigasi duplikasi akibat refresh halaman.

Catatan: pastikan backend juga menangani header idempoten dan mendokumentasikan logika retry di kontrak API.

Autentikasi dan Middleware Nuxt.js

Middleware auth yang konsisten penting agar setiap halaman yang membutuhkan token memiliki behavior error handling yang sama. Contoh plugin auth:

export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.hook('app:rendered', () => {
    // contoh hook global untuk refresh token jika perlu
  })

  nuxtApp.provide('authRequest', async (options) => {
    const token = useCookie('auth_token').value
    if (!token) {
      throw createError({ statusCode: 401, statusMessage: 'Token tidak tersedia' })
    }
    return useApiClient().request(options.path, {
      ...options,
      headers: { ...(options.headers ?? {}), Authorization: `Bearer ${token}` }
    })
  })
})

Middleware Nuxt (file middleware/auth.global.ts) bisa memeriksa token sebelum render page, kemudian memanggil metode $authRequest agar semua request API mengikuti autentikasi yang sama.

Pastikan middleware menangani error kontrak (misalnya 401/403) dengan mengosongkan cookie dan mengarahkan ke login, sesuai dokumentasi event error yang disetujui.

Validasi Webhook HMAC dan Callback

Webhook mengalir dari layanan eksternal ke Nuxt. Untuk menjaga integritas payload, verifikasi HMAC yang disepakati di kontrak menjadi wajib. Contoh endpoint API serverless di Nuxt (API route):

export default defineEventHandler(async (event) => {
  const rawBody = await readBody(event, { json: false })
  const secret = useRuntimeConfig().webhookSecret
  const expectedSignature = event.node.req.headers['x-signature']

  const computed = createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex')

  if (!timingSafeEqual(Buffer.from(computed, 'hex'), Buffer.from(expectedSignature ?? '', 'hex'))) {
    throw createError({ statusCode: 401, statusMessage: 'Signature tidak valid' })
  }

  const payload = JSON.parse(rawBody)
  if (!isValidPayload(payload)) {
    throw createError({ statusCode: 400, statusMessage: 'Payload tidak sesuai kontrak' })
  }

  // proses payload sesuai kontrak
})

Gunakan timingSafeEqual untuk mencegah serangan timing dan pastikan schema payload diekspor ke dokumentasi kontrak. Jika terjadi mismatch, respons harus konsisten dengan kontrak sehingga provider tahu status errornya.

Ringkas dan Saran Operasional

Agar Nuxt.js tetap sinkron dengan layanan eksternal, tim harus:

  • Memiliki folder dokumentasi kontrak (OpenAPI, contract test) yang di-sync dengan CI/CD.
  • Mengimplementasikan middleware auth + composable request yang mematuhi kontrak, menambahkan header idempoten, serta retry yang dapat dikonfigurasi.
  • Menangani error sesuai kontrak agar frontend tidak menebak status code baru.
  • Mengamankan webhook dengan HMAC dan validasi schema yang konsisten.

Debugging biasanya dimulai dari kontrak: periksa apakah schema OpenAPI mencakup status code yang diterima, telusuri header autentikasi yang dikirim, dan pantau ulang idempoten header untuk memastikan backend tidak menduplikasi log.

Dengan disiplin tersebut, Nuxt.js dapat menjaga kontrak API dan autentikasi tetap terjamin meski mengandalkan layanan eksternal.