Nuxtでのカスタム useFetch
Nuxt 3で外部APIを呼び出すためのカスタムフェッチャーを作成する方法。
Nuxtを使用していると、フロントエンドを作成して外部APIをフェッチすることがあります。その際、APIからのフェッチにいくつかのデフォルトオプションを設定したい場合があります。
$fetch
ユーティリティ関数(useFetch
コンポーザブルで使用)は、意図的にグローバルには設定できません。これは、アプリケーション全体のフェッチ動作の一貫性を保ち、他の統合(モジュールなど)が$fetch
のようなコアユーティリティの動作に依存できるようにするために重要です。
ただし、Nuxtには、API(または、呼び出すAPIが複数ある場合は複数のフェッチャー)用のカスタムフェッチャーを作成する方法が用意されています。
カスタム$fetch
Nuxtプラグインを使用して、カスタム$fetch
インスタンスを作成してみましょう。
$fetch
は、NuxtサーバーのベースURLの追加や、SSR中の直接関数呼び出し(HTTPラウンドトリップの回避)をサポートする、ofetchの設定済みインスタンスです。ここで、次のことを前提として説明します。
- メインAPIはhttps://api.nuxt.comです。
- JWTトークンは、nuxt-auth-utilsを使用してセッションに保存しています。
- APIが
401
ステータスコードで応答した場合、ユーザーを/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) {
// note that this relies on ofetch >= 1.4.0 - you may need to refresh your lockfile
options.headers.set('Authorization', `Bearer ${session.value?.token}`)
}
},
async onResponseError({ response }) {
if (response.status === 401) {
await nuxtApp.runWithContext(() => navigateTo('/login'))
}
}
})
// Expose to useNuxtApp().$api
return {
provide: {
api
}
}
})
このNuxtプラグインを使用すると、Vueコンポーネントから直接API呼び出しを行うために、useNuxtApp()
から$api
が公開されます。
app.vue
<script setup>
const { $api } = useNuxtApp()
const { data: modules } = await useAsyncData('modules', () => $api('/modules'))
</script>
useAsyncData
でラップすると、サーバーサイドレンダリング時(ハイドレーション時のサーバーとクライアント)の二重データフェッチを回避できます。カスタムuseFetch
/useAsyncData
$api
に必要なロジックができたので、useAsyncData
+ $api
の使用を置き換えるためのuseAPI
コンポーザブルを作成しましょう。
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
})
}
新しいコンポーザブルを使用して、クリーンなコンポーネントを作成しましょう。
app.vue
<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
の場合も同じ構造になります。現在、カスタムフェッチャーを作成するためのよりクリーンな方法について議論しています。 https://github.com/nuxt/nuxt/issues/14736を参照してください。