Пользовательский useFetch в Nuxt
При работе с Nuxt вы можете делать фронтенд и получать данные из внешнего API, и вам, возможно, захочется установить некоторые параметры по умолчанию для получения данных из вашего API.
Утилита $fetch
(используемая композаблом useFetch
) намеренно не является глобально настраиваемой. Это важно для того, чтобы поведение получения данных в вашем приложении оставалось последовательным, и другие интеграции (например, модули) могли полагаться на поведение основных утилит, таких как $fetch
.
Однако Nuxt предоставляет возможность создать пользовательский "фетчер" для вашего API (или несколько фетчеров, если у вас есть несколько API для вызова).
Пользовательский $fetch
Давайте создадим пользовательский экземпляр $fetch
с помощью плагина Nuxt.
$fetch
- это настроенный экземпляр ofetch, который поддерживает добавление базового URL вашего сервера Nuxt, а также прямые вызовы функций во время SSR (избегая HTTP-roundtrip).Давайте представим, что:
- Основной 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) {
const headers = options.headers ||= {}
if (Array.isArray(headers)) {
headers.push(['Authorization', `Bearer ${session.value?.token}`])
} else if (headers instanceof Headers) {
headers.set('Authorization', `Bearer ${session.value?.token}`)
} else {
headers.Authorization = `Bearer ${session.value?.token}`
}
}
},
async onResponseError({ response }) {
if (response.status === 401) {
await nuxtApp.runWithContext(() => navigateTo('/login'))
}
}
})
// Предоставляем в useNuxtApp().$api
return {
provide: {
api
}
}
})
С помощью этого плагина Nuxt, $api
выводится из useNuxtApp()
для осуществления вызовов API непосредственно из компонентов Vue:
<script setup>
const { $api } = useNuxtApp()
const { data: modules } = await useAsyncData('modules', () => $api('/modules'))
</script>
useAsyncData
позволяет избежать двойной выборки данных при SSR (сервер и клиентская гидратация).Пользовательские useFetch
/useAsyncData
Теперь, когда $api
имеет нужную нам логику, давайте создадим useAPI
composable, чтобы заменить использование 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
})
}
Давайте воспользуемся новым композаблом и получим красивый и чистый компонент:
<script setup>
const { data: modules } = await useAPI('/modules')
</script>
useFetch
, но та же структура идентична и для пользовательского useAsyncData
.