Nuxt でのカスタム useFetch

Nuxt で外部 API を呼び出すためのカスタムフェッチャーを作成する方法。

Nuxt で作業している場合、フロントエンドを作成して外部 API をフェッチすることがあります。その際、API からフェッチするためのいくつかのデフォルトオプションを設定したいと思うかもしれません。

useFetch コンポーザブルで使用される $fetch ユーティリティ関数は、意図的にグローバルに設定できません。これは、アプリケーション全体でフェッチ動作の一貫性を保ち、他の統合(モジュールなど)が $fetch のようなコアユーティリティの動作に依存できるようにするために重要です。

ただし、Nuxt は API 用のカスタムフェッチャーを作成する方法を提供します(複数の API を呼び出す場合は複数のフェッチャーも作成できます)。

カスタム $fetch

Nuxt プラグインを使用して、カスタムの $fetch インスタンスを作成しましょう。

$fetch は、以下の設定済みインスタンスです。ofetchこれは、Nuxt サーバーのベース URL を追加するだけでなく、SSR 中に直接関数呼び出しをサポートします(HTTP ラウンドトリップを回避します)。

ここでは、次のことを仮定しましょう。

  • メイン API はhttps://api.nuxt.com
  • JWT トークンをセッションに保存しています。nuxt-auth-utils
  • API が 401 ステータスコードで応答した場合、ユーザーを /login ページにリダイレクトします。
app/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/app.vue
<script setup>
const { $api } = useNuxtApp()
const { data: modules } = await useAsyncData('modules', () => $api('/modules'))
</script>
useAsyncData でラップすると、サーバーサイドレンダリング時の二重データフェッチングを防ぎます(サーバーとクライアントの両方でハイドレーション時に)。

カスタム useFetch/useAsyncData

$api に必要なロジックが組み込まれたので、useAsyncData + $api の使用を置き換えるための useAPI コンポーザブルを作成しましょう。

app/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/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 でも同じ構造が適用されます。
Docs > 4 X > Examples > Advanced > Use Custom Fetch Composable で、実際の例を読み、編集できます。
現在、よりクリーンな方法でカスタムフェッチャーを作成できるように議論中です。詳細は以下をご覧ください。https://github.com/nuxt/nuxt/issues/14736.