nuxt logo

ドキュメント翻訳(非公式)

Nuxt.js
Version:v3.17

Nuxt におけるカスタム useFetch

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

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

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

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

カスタム $fetch

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

$fetchofetch の設定済みインスタンスであり、Nuxt サーバーのベース URL を追加したり、SSR 中に直接関数呼び出しをサポートしています(HTTP ラウンドトリップを回避)。

ここでは以下のように仮定します:

  • メイン 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) {
        // これは ofetch >= 1.4.0 に依存しています - ロックファイルを更新する必要があるかもしれません
        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
    }
  }
})

この Nuxt プラグインを使用すると、$apiuseNuxtApp() から公開され、Vue コンポーネントから直接 API 呼び出しが可能になります:

app.vue
const { $api } = useNuxtApp()
const { data: modules } = await useAsyncData('modules', () => $api('/modules'))

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
const { data: modules } = await useAPI('/modules')

返されるエラーのタイプをカスタマイズしたい場合も可能です:

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 の場合も同じ構造です。

サンプルコードの編集とプレビューexamples > advanced > use-custom-fetch-composable

カスタムフェッチャーを作成するためのよりクリーンな方法を見つけるために現在議論中です。詳細は https://github.com/nuxt/nuxt/issues/14736 を参照してください。