Пользовательский useFetch в Nuxt
Во фронтенде на Nuxt часто вызывают внешнее API; удобно задать для этих запросов общие параметры по умолчанию (базовый URL, заголовки, обработка ошибок).
Утилита $fetch (используемая композаблом useFetch) намеренно не является глобально настраиваемой. Это важно для того, чтобы поведение получения данных в вашем приложении оставалось последовательным, и другие интеграции (например, модули) могли полагаться на поведение основных утилит, таких как $fetch.
Nuxt позволяет завести отдельный экземпляр «фетча» под ваш API — или несколько, если бэкендов несколько.
Пользовательский $fetch
Создайте экземпляр $fetch в плагине Nuxt.
$fetch — это настроенный экземпляр ofetch, который поддерживает добавление базового URL вашего сервера Nuxt, а также прямые вызовы функций во время SSR без лишнего HTTP-запроса туда-обратно.Допустим:
- основной API — https://api.nuxt.com;
- мы храним JWT-токен в сессии с помощью nuxt-auth-utils;
- если API отвечает кодом состояния
401, перенаправляем пользователя на страницу/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) {
// нужен ofetch >= 1.4.0; при необходимости обновите lockfile
options.headers.set('Authorization', `Bearer ${session.value?.token}`)
}
},
async onResponseError ({ response }) {
if (response.status === 401) {
await nuxtApp.runWithContext(() => navigateTo('/login'))
}
},
})
// Предоставляем в useNuxtApp().$api
return {
provide: {
api,
},
}
})
Плагин пробрасывает $api в useNuxtApp() — вызывать API можно прямо из компонентов:
<script setup>
const { $api } = useNuxtApp()
const { data: modules } = await useAsyncData('modules', () => $api('/modules'))
</script>
useAsyncDataснижает риск двойного запроса при SSR (один раз на сервере и согласованная гидратация на клиенте).Пользовательские useFetch/useAsyncData
Когда логика $api готова, оберните её в композабл useAPI, чтобы не дублировать 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,
})
}
Пример компонента с новым композаблом:
<script setup>
const { data: modules } = await useAPI('/modules')
</script>
Чтобы задать тип возвращаемой ошибки, можно сделать так:
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,
})
}
useFetch, но та же структура идентична и для пользовательского useAsyncData.