【Vue.js】Web API通信のデザインパターン (個人的ベストプラクティス)

# はじめに
Vue.jsを使用したアプリケーションでのWeb API呼び出しのデザインパターンについて調べてみました。

しかし検索して出てくるチュートリアルやサンプルは、コンポーネント内でaxiosをインスタンス化していたり、Vuexの中でaxiosを使用するというサンプルがほとんどでした。

しかし実際のプロダクトでこれをしてしまうと

- コンポーネント内でAPIアクセスの直書きによって単体テストが困難に
- Vuex(actions)の肥大化(使い回さない処理はStoreに記述しないほうがいいとする文献もある)
- API通信部分をPureJSでモジュール化しても依存度がイマイチ下がらない（コンポーネントでモジュールをインポートするため）。

などなど問題になることが多そうでした。
ある日、[Jorge](https://medium.com/@jnietou)氏が投稿した「[Vue API calls in a smart way](https://medium.com/canariasjs/vue-api-calls-in-a-smart-way-8d521812c322)」という記事にたどり着きました。
結果から言うとこのデザインパターンは自分にはベストな方法であったため、著者の許可を得て紹介します。以下拙訳(一部意訳)です。

# ここから翻訳
長い間、APIを呼び出すための様々な方法を公開したいと思いました。この章では私にとって最適なパターンについて話したいと思います。**RepositoryFactory**を紹介させてください。

私はこのアプローチが非常によくスケールでき、ほぼいつも上手くいくため大好きです。

### なぜかを説明しましょう:
1つは[リポジトリパターン](https://docs.microsoft.com/en-gb/dotnet/standard/microservices-architecture/microservice-ddd-cqrs-patterns/infrastructure-persistence-layer-design?view=aspnetcore-2.1#the-repository-pattern)を使用して、データを返す以外のロジックなしで分離された方法でリソースにアクセスできます。
もう1つは[ファクトリパターン](https://en.wikipedia.org/wiki/Factory_method_pattern)を使用して、各ケースで必要なリポジトリ、または環境のロジックをインスタンス化します。必要に応じて、ファクトリが**モックリポジトリと本番リポジトリのどちらをインスタンス化するかを決定できる**という利点があります。

各コンポーネント内にaxiosのインスタンスを使用したサンプルをどれだけ見たでしょうか。
**私はそれを見るたびに毎回疑問に思います🤔**

- 呼び出し処理を再利用するときはどうなりますか？
- エンドポイントが変わったときはどうなりますか？
- ほかのプロジェクトでAPI呼び出し処理を再利用したい場合はどうなりますか？
- コードをリファクタしたり、Vuexのactionsに移動する場合はどうなりますか？
- 複数のリソースがありますが、4つの異なるエンドポイントを定義する必要がありますか？
- テストのためにモックなどのエンドポイントをどのように扱うことができますか？

![0_5m-dDbSZ3gb8oaCJ.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149212/8088ea60-19e9-37ef-58ac-20a24f0a964b.gif)
**30個のファイルを変えるよりも１個のファイルを変えるほうが簡単でしょう？🤯**

### 正しい方法
このケースではコードをシンプルにして、さまざまなリソースを定義するために、POJO（Plain Old JavaScript Objects）を使用します。（もちろん、必要に応じて**クラス**を使えます）*axiosの設定*を定義しましょう。ファイル名はリソースの接続を確立する責任があるため、**Repository.js**とします。

**service**または単に**API**という用語を使う人もいますが、Repositoryがその機能を最もよく定義しているように思えます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149212/22dc0521-1883-e4c8-3d2d-7ca5130fb012.png)

それから、それぞれのエンティティのリソース定義をする必要があります。
例えばブログがあるとしましょう。**posts**エンティティがあり、すべてのCRUD操作を独自のリポジトリファイルに定義できます。
**postsRepository**はこんな感じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149212/b2ce5b41-45fa-4dc7-febf-d9b084118a5d.png)

そしてファクトリを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149212/b4f969c5-92e0-cb31-c3c1-ceaea02c96da.png)

見ての通りリクエストしたリソースのシンプルなオブジェクトが返されます。
この段階で**get（）メソッド**にさらにロジックを追加して複数の環境を扱ったり、**モックリポジトリ**をインポートしたりできることに気付いたでしょう。

たとえば、現在私がいる会社（[Snap.hr](https://snap.hr/)）では、いくつかの異なる環境が必要です。環境に応じて、モックまたは対応するエンドポイントに変更します。これはあなたが望むものと同じような複雑さでしょう。
でもこの例ではシンプルにしましょう🙃

.vueファイルの[SFC](https://vuejs.org/v2/guide/single-file-components.html)でどのように使用するかお見せしましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149212/77adba97-7894-46ea-a586-14d2ac191f60.png)
ロジックは完全に分離されているので、異なるパラダイムを持つ別のエンドポイントをGraphQLとして使用することもできます。

### 💡結論
常に銀の弾丸は存在しないものです。このパターンは私のほとんど全部のプロジェクトでうまくいっていますが、あなたのプロジェクトにとって最適という意味ではありません。

しかし、以下のアドバンテージがあると思います。

- 簡単な方法でテスト可能なコードを実行できます。
- コンポーネントのコードがきれいになります。
- 簡単に拡張できますよね？
- [DRY](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself)を保つことができます。

[実用的なサンプル](https://codesandbox.io/s/o93j2y4mj9)を**Codesandbox** で作成し、このアプローチを実際に実装してみました。
この種の手法を既に使用しているのであれば、ぜひお聞かせください。
👋

提案や質問がありますか？お気軽にコメントや[Twitter](https://twitter.com/jnietou)でコンタクトください！

この記事は[2018年に最も人気のあったVue.js記事](https://www.monterail.com/blog/top-vuejs-development-articles-2018)の１つに選ばれました。

---
ここまで翻訳

# 謝辞(Appreciation)
Dear Jorge
Thank you for your amazing article!