14
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

Organization

Nuxt.jsのAPI通信で共通のエラーハンドリングを行う

これはなに

Nuxt.jsでのaspidaを使ったAPI通信について、
API呼び出し箇所でエラーハンドリングするのではなく、共通的にエラーハンドリングする方法を記載します。

また、一部のAPI呼び出しにおいて、例外的に共通のエラーハンドリングを実行しないようにする方法も記載しています。

生のaxiosを使っている場合どうやるかは記載してません。

先に結論

  • pluginsにてaxios.onError()を設定することで共通のエラーハンドリングをかける
  • API呼び出し時のconfigに独自の値を入れることで、共通のエラーハンドリングで処理を分岐できる
  • configに独自の値を入れるために型を拡張する必要がある

やり方

nuxt.config.js

axiosモジュールの追加と、後述するpluginの読み込みを追加します。

nuxt.config.js

const nuxtConfig: Configuration = {
  // 略
  plugins: [
    '@/plugins/axios.ts',
  ],
  // 略
  modules: [
    '@nuxtjs/axios',
  ],
  // 略
}

plugins

plugins/axios.jsを作成して、axiosの設定を追加しましょう。

plugins/axios.ts
import { Context } from '@nuxt/types'
import { AxiosError, AxiosRequestConfig } from 'axios'
import Rollbar from 'rollbar'


// AxiosRequestConfigを拡張して、Nuxtのエラーページを表示するかどうかのフラグを保持できるようにする
export type CustomRequestConfig = AxiosRequestConfig & {
  dontDisplayErrorPage?: boolean
}

export default ({ $axio, error }: Context) => {
  // ここでaxiosの共通設定を行う
  $axios.defaults.timeout = 10000
  // NOTE: ここでCustomRequestConfigのプロパティもデフォルト値を設定できれば良いが、型の制約上難しそうだった

  // axiosのエラーハンドリングを追加する
  $axios.onError((axiosError: AxiosError) => {
    const res = axiosError.response
    const status = res?.status ?? 500

    if ((axiosError.config as CustomRequestConfig)?.dontDisplayErrorPage) {
      // api利用時にconfigとして`dontDisplayErrorPage: true`を渡した時のみエラーページの表示をスキップする
      return
    }

    // 共通で実行したいエラー処理
    error({ statusCode: status }) // エラーページを表示
  })
}

共通エラー処理追加

$axios.onError()でエラー時の共通処理を書くことができます。
ただし、このままだと全てのAPI呼び出しにおいて、エラー時に同じ処理をしてしまうので、あるAPIだけ違った処理にしたい場合などに対応できません。
そこで、axios呼び出し時のconfigに独自の設定値を渡し、onErrorのタイミングで取得することで処理の分岐を実現します。

axiosの設定値(AxiosRequestConfig)型の拡張

export type CustomRequestConfig = AxiosRequestConfig & {
  dontDisplayErrorPage?: boolean
}

このようにしてプロパティを追加することができます。

api呼び出すところ

共通エラーハンドリングを利用する

共通エラーハンドリングをしたい場合は、普通にaspidaを使ってAPIを呼び出すだけです。
エラーが発生したら、共通のエラーハンドリングが実行されます。

例外的にAPI別にエラーハンドリングをする

例外的に共通エラーハンドリングをスキップしたい場合は以下のようにします。

call_api.ts
// 呼び出し処理の例
import api from '@@/apis/$api'
import { AxiosInstance } from 'axios'
import aspida from '@/libs/aspida-shim'


export const callAPI = (axios: AxiosInstance) => {
  // <T>にカスタマイズした設定型を入れる
  const client = api<CustomRequestConfig>(aspida(axios))

  client.api.hogehoge.$get({
    config: {
      dontDisplayErrorPage: true // 独自のエラーハンドリングをするのでエラーページの表示をしない
      timeout: 60000, //通常のオプションも上書きできる
    }
  })
  .then(() => {
     console.log('success!')
  })
  .catch((error: AxiosError) => {
     console.dir(error)
     // ここに自前でエラーハンドリングを書く
     // `dontDisplayErrorPage` オプションをつけているのでエラーページの表示処理はスキップされる
  })
}

説明

typescriptを使用している場合は、独自のconfig値を渡そうとしても
configの型がAxiosRequestConfig型でないためエラーになってしまいます。
これを解決するには、以下のようにします。

  // <T>にカスタマイズした設定型を入れる
  const client = api<CustomRequestConfig>(aspida(axios))

ここのapi = '@@/apis/$api'はaspidaがビルドしたAPIの型情報が記載されたファイルです。
apiは以下のような型定義になっていて、Tに渡した型が、configの型となることがわかります。

@@/apis/$api.ts
const api = <T>({ baseURL, fetch }: AspidaClient<T>) => {
// 略
  return {
    api: {
      hogehoge: {
        get: (option?: { config?: T }) =>
          fetch<Methods0['get']['resBody']>(prefix, PATH0, GET, option).json(),
// 略

<T>カスタマイズした設定オブジェクトの型(CustomRequestConfig)を入れてやれば
独自に定義した設定値を使うことができます。

まとめ

  • pluginsにてaxios.onError()を設定することで共通のエラーハンドリングをかける
  • API呼び出し時のconfigに値を入れることで、共通エラーハンドリングで処理を分岐できる
  • configに独自の値を入れるために型を拡張する必要がある

以上、参考になりましたら幸いです。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
14
Help us understand the problem. What are the problem?