【Nuxt.js】axiosのAPI共通処理をラップし、Repositoryパターンを実現する(TypeScript)

2021-01-08

やりたいこと

Nuxt.jsのaxiosでサーバーのREST APIを呼び出す処理を、classにまとめて、いろんなコンポーネントからthisで呼び出せるようにしたい

例)

APIのカテゴリー毎にRepositoryクラスを作って・・・・。

componentからthisで呼び出せるようにする!

 

1.axiosをインストールする

以下コマンドでaxiosを入れる。

package.jsonにaxiosが入っていることを確認

 

■/package.json

2.axiosをモジュール登録する

@nuxtjs/axiosが有効になるように、nuxt.config.jsの設定をします。

 

■/nuxt.config.js

3.repositoryフォルダを作成し、UserRepository.tsを作成する。

まずは、repositoryフォルダ(apiフォルダでもdomainフォルダでも名前は自由)を作成し、Userに関するAPI処理(api通信し、レスポンスを特定の型に整形してコンポーネントへ返す)を行うRepositoryクラスを作成しておきます。

 

■/repository/UserRepository

Repositoryクラスは★3-1のように、pluginからnew(引数NuxtAxiosInstance)して使えるようにしておきます。

4.pluginsフォルダにaxios.tsを作成する。

処理を共通化するために、プラグインを作成します。

まず、plugins/axios.tsを作成して、共通のヘッダーの設定や、レスポンスが帰ってきた時の共通処理を記載しておきます。

 

■plugins/axios.ts

長いので、ブロック毎に区切って説明します。

 

1.Plugin型でプラグイン本体を作成

Repositoryクラスもimportしておく。Repositoryクラスが増えた時は、随時ここにimportを追加していきます。

2.setHeaderを利用して、リクエスト時のヘッダーを指定する

Interceptorsという機能を利用し、axiosの共通処理を作成していきます。

setHeader を使用すると、リクエストするときのヘッダーを指定することができます。

参考)Helpers – Axios Module

3.onErrorを使用して、サーバーからエラーレスポンスが返ってきた時の処理を記載する。

必要であれば、Interceptorsの onError を利用して、サーバーからレスポンスが返ってきた時の処理を共通化することができます。

参考)Helpers – Axios Module

4.Repositoryクラスをinjectする。

ここが一番のミソです。

UserRepositoryに NuxtAxiosInstance を引数に渡してインスタンス化し、injectします。

inject を使うことで、Nuxt.jsのいろいろな場所から共通で利用したい関数や値を this.$XXXX  で呼び出すことができます。

コンポーネントから import でripositoryを読み込むのもアリですが、injectを使えば、Repositoryの差し替えなどが発生した場合楽になります。(このファイルだけ書き直せばいいので。)

参考) Nuxt.jsのinjectを使ってDIする – CYDAS Developer’s Blog

 

5.Vueインスタンスや、Contextの型を拡張する。

5を書かなくても動くのですが、TypeScriptで開発している以上、型定義が必須となります。

コンポーネント上で呼び出した時、VSCode上にも Property '$userRepository' does not exist on type 'CombinedVueInstance<Vue,・・ というエラーが出てしまいます。

なので、Vueインスタンス上で $userRepository を使用できるように、型を拡張します。(★5-1)

Repositoryクラスが増えた場合は readonly $xxxRepository: XxxRepository を追加していきます。

参照 )プラグインで使用するための型拡張

 

あわせて、this.$nuxt.context からも使用できるように、’@nuxt/types’の型も拡張します(★5-2)

参考)プラグイン – Nuxt TypeScript

これで、コンポーネントからUserAPIを使用する準備が整いました。

 

5.コンポーネントから呼び出す。

メソッドで呼び出す場合(thisで呼び出す)

asyncDataなどから呼び出す場合(contextで呼び出す)

以上で、やりたかったことを実現することができました!

 

6.まとめ

axiosの処理を共通化する際、いままで、以下のサイトを参考にしていました。

Nuxt.jsでaxiosの共通処理を作成し、API呼び出し処理をラップして使用する – Qiita

ただ、

・ESLintを入れた際に、 export let axios  の部分が、 import/no-mutable-exports エラーとなってしまう

・各コンポーネントでimportする必要がでてくる

などのモヤモヤで、悩んでいたところ、山地 さん (@tom_nobu) / Twitter がinjectを使ってfirebaseの処理を共通化していたのを見て真似してみました!感謝🙏

あとは、injectしてしまうと、Repositoryクラスのメソッドの参照がVSCodeの機能で追えなくなっちゃうのでどこからRepositoryを使っているのか分からなくなってしまうのを解決したいですね・・。

でも、今のところ、Repositoryクラスはpagesからのみ使用する!と決めているので特に支障はなくこのやり方で進めていきたいと思います!

あとは、サーバーサイドから送られてくるanyのデータをどうやってModelに落とし込むか、ベストな方法を検討していきたい。

そちらが解決したら、素敵なVue+TSライフを送れそうな気がする!

 

—————

この記事がお役に立てたら、是非シェアをお願いします^^