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
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:
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:
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:
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.
Actualmente estamos discutiendo para encontrar una manera más limpia de permitirte crear un fetcher personalizado, ver https://github.com/nuxt/nuxt/issues/14736.
※Esta página es una traducción no oficial de la documentación oficial de Nuxt.js.
La página correspondiente en la documentación oficial está aquí:
https://nuxt.com/docs/3.x/guide/recipes/custom-usefetch