Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
2
Help us understand the problem. What is going on with this article?
@Kanahiro

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

この記事について

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

2
Help us understand the problem. What is going on with this article?
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
Kanahiro
GISを中心に勉強中、いろいろ作っています。
MIERUNE
位置情報の技術情報や豆知識をMIERUNEがお届けします!。位置に関する可視化や解析に関するご相談がございましたらwebまでぜひご連絡ください!

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
2
Help us understand the problem. What is going on with this article?