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