LoginSignup
9
7

More than 3 years have passed since last update.

Vue+Vue router+AxiosによるAPIエラーハンドリングとページ遷移の実装パターン

Last updated at Posted at 2021-01-08

この記事について

  • Vueコンポーネント内やVuexのAction内などあちこちでAxiosによるAPIリクエストをしていると、エラーハンドリングを個別に記述しなければならなくなり、DRYではなくなってしまう
  • APIリクエストでエラーが発生した場合に特定のページに遷移させたいのに、Vueインスタンスの外からは$router.push()が呼べない

この記事では、上記のよくある問題をなるべくDRYかつシンプルに解決した方法を述べます。

検証環境

  • Vue2系(Options API、でもcomposition APIでも動くと思う)
  • Vuex(今回の実装には関係ないけれど、Vuexを組み合わせる事も出来る)
  • Vue Router
  • JavaScript

APIリクエストを1箇所で管理する

参考:https://kntmr.hatenablog.com/entry/2018/02/28/200112

各所でAxiosをそのまま用いて非同期通信をすると、それぞれでエラーをcatchしなければなりません。それは辛いので、別にモジュールを用意してAxiosをラップした関数を定義し、その中でエラーハンドリングを行います。基本的に参考サイトのままですが、関数の部分だけ、get, postなどメソッドで分けずに、configで指定するようにしています。

/src/api/index.js

import axios from 'axios'

const debug = process.env.NODE_ENV !== 'production'

const onSuccess = (resp) => {
  if (debug) {
    console.log(' << ' + JSON.stringify(resp.data))
  }
  return Promise.resolve(resp.data)
}
const onError = () => {
  throw new Error('API error.')
}

// リクエストメソッド問わず同じ関数を用いる
const api = (config) => {
    if (debug) {
        console.log(`${config.method} ${config.url} >> ${config.params}`);
    }
    return axios(config)
        .then(onSuccess)
        .catch(onError);
};

export default api;

コンポーネントやVuexでaxios()を使っていた箇所をapi()に置き換えることで、エラーハンドリングの記述が1箇所・1回で済みます、イッツDRY。

エラー時にVue Routerでページ遷移

上記まででエラーハンドリングは1箇所で管理することが出来ました。

さてその際、APIアクセスが失敗した時に、Vue Routerの特定にページに遷移させたい時があります。なので、上記の/src/api/index.jsonError()で、$router.push()したい訳です。

ですがコンポーネントの外(=Vueインスタンスの外)から$router.push()は使うことが出来ません。なのでちょっと工夫します。

Vueインスタンスのexport

Vueプロジェクトのエントリーポイントである/src/main.jsは、Vue CLIでプロジェクトを生成した際は下記のようにVueインスタンスを生成・HTMLを描画しています。

/src/main.js

// 略

new Vue({
  render: h => h(App),
}).$mount('#app')

ここで、Vueインスタンスをエクスポートします。

/src/main.js

// 略

const vm = new Vue({
  render: h => h(App),
}).$mount('#app')

export default vm;

ここでexportしているvmは、Vueインスタンスのシングルトンです。どこでimportしても常に同一のインスタンスを参照します。

参考:https://qiita.com/NeGI1009/items/f8b17d856a4b15b1ecbc

なので/src/main.jsをimportすればどこからでもVueインスタンスにアクセス出来る訳です。

とはいえ、様々な場所で無秩序にVueインスタンスを操作するのは避けるべきと考えます。

apiモジュールでVueインスタンスにアクセス

/src/api/index.js

import axios from 'axios'

// Vueインスタンス
import vm from '../main';

//略

const onError = () => {
  //エラー時にルートへ遷移
  vm.$router.push('/')
  throw new Error('API error.')
}

//略

この時、Vuex APIにもRouterと同様、vm.$storeでアクセス出来ます。つまりVuexに保存した変数を取得出来るし(getter)、setterやactionを発火させる事も出来ます。

以上でAPIリクエスト時のエラーハンドリングの集中管理およびエラー時のページ遷移が実現しました。あちこちに散逸しがちなエラーハンドリングに対する悪くない実装パターンではないでしょうか。

9
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
7