nuxt logo

Traducción de Documentación (No Oficial)

Nuxt.js
Version:v3.17

Custom useFetch en Nuxt

Cómo crear un fetcher personalizado para llamar a tu API externa en Nuxt.

Cuando trabajas con Nuxt, podrías estar desarrollando el frontend y obteniendo datos de una API externa, y podrías querer establecer algunas opciones predeterminadas para obtener datos de tu API.

La función utilitaria $fetch (utilizada por el composable useFetch) intencionalmente no es configurable globalmente. Esto es importante para que el comportamiento de obtención de datos en toda tu aplicación se mantenga consistente, y otras integraciones (como módulos) puedan confiar en el comportamiento de utilidades centrales como $fetch.

Sin embargo, Nuxt proporciona una manera de crear un fetcher personalizado para tu API (o múltiples fetchers si tienes varias APIs para llamar).

$fetch personalizado

Vamos a crear una instancia personalizada de $fetch con un plugin de Nuxt.

$fetch es una instancia configurada de ofetch que admite agregar la URL base de tu servidor Nuxt, así como llamadas de función directa durante SSR (evitando viajes de ida y vuelta HTTP).

Supongamos aquí que:

  • La API principal es https://api.nuxt.com
  • Estamos almacenando el token JWT en una sesión con nuxt-auth-utils
  • Si la API responde con un código de estado 401, redirigimos al usuario a la página /login
plugins/api.ts
export default defineNuxtPlugin((nuxtApp) => {
  const { session } = useUserSession()

  const api = $fetch.create({
    baseURL: 'https://api.nuxt.com',
    onRequest({ request, options, error }) {
      if (session.value?.token) {
        // nota que esto depende de ofetch >= 1.4.0 - podrías necesitar actualizar tu archivo de bloqueo
        options.headers.set('Authorization', `Bearer ${session.value?.token}`)
      }
    },
    async onResponseError({ response }) {
      if (response.status === 401) {
        await nuxtApp.runWithContext(() => navigateTo('/login'))
      }
    }
  })

  // Exponer para usar useNuxtApp().$api
  return {
    provide: {
      api
    }
  }
})

Con este plugin de Nuxt, $api se expone desde useNuxtApp() para realizar llamadas a la API directamente desde los componentes de Vue:

app.vue
const { $api } = useNuxtApp()
const { data: modules } = await useAsyncData('modules', () => $api('/modules'))

Envolver con useAsyncData evita la doble obtención de datos al hacer renderizado del lado del servidor (servidor y cliente en hidratación).

useFetch/useAsyncData personalizado

Ahora que $api tiene la lógica que queremos, vamos a crear un composable useAPI para reemplazar el uso de useAsyncData + $api:

composables/useAPI.ts
import type { UseFetchOptions } from 'nuxt/app'

export function useAPI<T>(
  url: string | (() => string),
  options?: UseFetchOptions<T>,
) {
  return useFetch(url, {
    ...options,
    $fetch: useNuxtApp().$api as typeof $fetch
  })
}

Vamos a usar el nuevo composable y tener un componente limpio y ordenado:

app.vue
const { data: modules } = await useAPI('/modules')

Si deseas personalizar el tipo de cualquier error devuelto, también puedes hacerlo:

import type { FetchError } from 'ofetch'
import type { UseFetchOptions } from 'nuxt/app'

interface CustomError {
  message: string
  statusCode: number
}

export function useAPI<T>(
  url: string | (() => string),
  options?: UseFetchOptions<T>,
) {
  return useFetch<T, FetchError<CustomError>>(url, {
    ...options,
    $fetch: useNuxtApp().$api
  })
}

Este ejemplo demuestra cómo usar un useFetch personalizado, pero la misma estructura es idéntica para un useAsyncData personalizado.

Editar y previsualizar el código de ejemploexamples > advanced > use-custom-fetch-composable

Actualmente estamos discutiendo para encontrar una manera más limpia de permitirte crear un fetcher personalizado, ver https://github.com/nuxt/nuxt/issues/14736.