質問: 質問 == SPA開発におけるAPI設計なのですが、何が良いのかわかりません。 特にGETメソッドのエンドポイントに関してです。 特定のクライアント用のAPIなので、汎用的なものではなく、ある程度、クライアントを意識したもので良いという前提があると思うので、 画面で必要な情報を全て返すAPIエンドポイントを用意してあげるのが良いのでしょうか? それとも、リソース単位のAPIをクライアントに提供して、クライアント側では必要に応じて、受け取った情報を用いて、計算、判断、加工などの処理を行ってもらうのが良いのでしょうか? もしくは、「要はバランスだよね」おじさん的な感じになるのでしょうか!? 前提、ビジネスロジックはバック側に持たせるで良いと思うのですが、画面依存させないAPI(リソース単位のAPI)を提供しているとどうしても、フロント側でリソースAの情報の一部と、リソースBの情報の一部をそれぞれ組み合わせて、加工、判断、計算をしないといけないような場面が出てきてしまうと思っています。 例えば、ログインユーザーのロールがXYZというロールで、かつ、帳票が生成済みの場合であれば、ダウンロードボタンを表示、または、活性化させたいような場合、ユーザーリソースに含まれるロール情報と、帳票情報に含まれるステータスの両方をみて、ダウンロード可能かどうかをフロント側で判断しないといけないと思います。 EvansのDDD本にはアンチパターンとしてSmart UIなる表現がありますし、最近、ツイッター界隈ではフロントエンドはJSON色付け係に徹するべなる主張も見かけまして、SPA開発におけるAPIやフロントエンド側のStore設計はどうあるべきなのか、混乱してきたのが質問の背景になります! ※ EvansのDDD本にあるSmart UIのUIはViewとControllerの両方を含んだプレゼンテーション層を指していると解釈しています。 以下、メリデリ考えてみました。 画面単位のAPIエンドポイントを用意する場合 ---------------------- ### 前提 画面単位のAPIエンドポイントとは、例えば、このteratailの個別質問詳細ページの場合だと、このページの表示に必要な情報(質問、回答一覧、関連質問一覧など)を1つのエンドポイントがまとめて返してくれるようなものをイメージして言っています。 ### メリット * フロント側は単に表示だけしていれば良く、バック側にビジネスロジックをすべて寄せることができる(あるとしても表示に関するフォーマットのロジックを持つくらい) ### デメリット * 画面側の表示項目に変更が発生した場合など、API側の改修も必要になる * APIが画面に依存するかたちになる * 画面毎にAPIを叩く必要があるので、リソース単位のレスポンスと違って、既に取得済みのAPIレスポンスを使い回すことが出来ない * ビジネスロジックがバックとフロントの両方に散らばってしまうことになる(フロント側に関しては、フロント側の各画面でビジネスロジックが散らばらないように、store側にビジネスロジックを寄せることで、複数の画面に同じロジックが散らばることは避けられる) * 画面毎に対応する画面用のAPIエンドポイントを用意するので、似たような情報を含んだ情報を返すAPIエンドポイントが増えて気持ち悪い気がする * 画面毎に対応する画面用のAPIエンドポイントを用意するので、APIエンドポイントが増えがち * クライアントがブラウザー、アプリ、CLIと複数ある場合、クライアント毎に表示する情報が異なると思われるので、さらにAPIエンドポイントが増える リソース単位のAPIエンドポイントを用意する場合 ------------------------ ### 前提 リソース単位のAPIエンドポイントとは、例えば、このteratailの個別質問詳細ページの場合だと、このページに対応した質問情報を返すエンドポイントがあったり、回答一覧を返すエンドポイントがあったり、関連した質問情報を返すエンドポイントがそれぞれ存在しているようなものをイメージしています。 ### メリット * 画面側の表示項目に変更が発生した場合、フロントが既にバックから受け取っているデータを用いて、計算、加工することでAPIの改修が不要になることもある * 既に取得済みのAPIレスポンスをキャッシュして使い回すことができる場合がある(キャッシュして問題ないものに限る) ### デメリット * フロント側で一部、ビジネスロジックを持つことが発生し得る。(独り言:リソース単位でフロントにレスポンス返すと、フロントでビジネスロジックを本当に持ち得えるのか?その処理はフロント側にあっても別に問題ないような処理だったりしないのか?つまり、ビジネスロジックであるのかどうか? 改めて、ビジネスロジックとは何かの定義と具体例を挙げて、検討した方が良さそう) リソース単位のAPIエンドポイントと画面単位のAPIエンドポイントの両方を用意する??? -------------------------------------------- メリデリ挙げてみて、両方のパターンの組み合わせを用意するのはどうなのだろうと思いつきました。 こういうのって、実際、やってたりするのでしょうか? 例えば、リソース単位のAPIを叩くのを基本としつつも、そのAPIでは取得出来ない画面固有の差分を取得するAPIエンドポイントを別途用意するみたいなイメージです。 よくわかっていないけど、BFF ??? ------------------- BFFがあまりなんだかよくわかっていないですが、リソース単位のAPIエンドポイントは用意して、フロントエンド側の個々の画面に必要な情報をまとめたレスポンスを返すAPIエンドポイントをBFFに用意する?
回答: 私の場合ですが画面単位とリソース単位の中間の設計にします。 > > もしくは、「要はバランスだよね」おじさん的な感じになるのでしょうか!? > > > やはりこうなると思います。 理由としては ・APIのコマンド数はできるだけ抑えたい →コマンド数増大は管理リスクも増大する ・ただ1度のAPIコマンドで大量データが取得されるのは困る。 →セキュリティの面でも一度に取得させたくない →明細結果などはpageなどで一定量で区切りさせ処理する ・また1度のAPIコマンドですべて処理されるのも困る。 エラー発生時の対応が難しくなるのと、コマンドコピーされた場合のリスクが高くなる。 ・拡張性は残したい →あまりまとめすぎると影響が大きくなるので分散しておきたい。 処理単位としては **単票形式画面(更新あり)** 認証用API(共通) メイン読込用API(1レコードのみ) 選択リスト読込用API(コンボボックスなどのリスト用共通) 更新時データ送信用API(あくまでデータの送信のみ) 更新用データDB登録用API(ビジネスロジックを与えDBに登録する) **明細形式画面(更新なし)** 認証用API(共通) メイン読込用API(複数行だがページ単位とし一度に取得できる件数を絞る) 質問者様がおっしゃられているように一部のビジネスロジックは JS側でカバーしないといけませんがメインはサーバ側。 ただし一回で登録させるのではなく2回に分ける。 (2回に分けた方がセキュリティ上も開発上も楽になる) メイン読込用APIは画面の種類分用意 画面に必要ない余計な項目の値を通信したくないのと 共用にすると変更時の影響度が高くなる。 (共通化はサーバ内処理でとすればよい) 自分が設計したときはこの様なコンセプトでした。 あと個人情報の管理の観点から通信上は暗号化で行いJS側で復号しないといけないのが 意外と手間でしたね。 こうやって書いてみると機能単位の設計なるという事でしょうか。