質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Vue.js

Vue.jsは、Webアプリケーションのインターフェースを構築するためのオープンソースJavaScriptフレームワークです。

SPA(Single-page Application)

SPA(Single-page Application)は、単一のWebページのみでコンテンツの切り替えができるWebアプリケーションもしくはWebサイトです。ブラウザでのページ遷移がないため、デスクトップアプリケーションのようなUXを提供します。

ドメイン駆動設計

ドメイン駆動設計(Domain-driven design, DDD)とは、ソフトウェアの設計手法、および設計思想や哲学のことです。ドメインモデル構築の際に、設計上の判断を決定する枠組みとドメイン設計に関して議論するボキャブラリを提供するものです。

API

APIはApplication Programming Interfaceの略です。APIはプログラムにリクエストされるサービスがどのように動作するかを、デベロッパーが定めたものです。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

Q&A

解決済

2回答

6656閲覧

SPA開発におけるAPI設計ってどういうものが好ましいのでしょうか?

murabito

総合スコア108

Vue.js

Vue.jsは、Webアプリケーションのインターフェースを構築するためのオープンソースJavaScriptフレームワークです。

SPA(Single-page Application)

SPA(Single-page Application)は、単一のWebページのみでコンテンツの切り替えができるWebアプリケーションもしくはWebサイトです。ブラウザでのページ遷移がないため、デスクトップアプリケーションのようなUXを提供します。

ドメイン駆動設計

ドメイン駆動設計(Domain-driven design, DDD)とは、ソフトウェアの設計手法、および設計思想や哲学のことです。ドメインモデル構築の際に、設計上の判断を決定する枠組みとドメイン設計に関して議論するボキャブラリを提供するものです。

API

APIはApplication Programming Interfaceの略です。APIはプログラムにリクエストされるサービスがどのように動作するかを、デベロッパーが定めたものです。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

0グッド

1クリップ

投稿2020/10/01 13:17

編集2020/10/01 23:44

質問

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に用意する?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

画面単位とリソース単位がかけ離れる状況ってなんですか?ひとつの画面に二つのリソースが必要ならAPI二つ叩くだけにした方がAPI利用する側も提供する側も仕様の共有し易いですよね?
という疑問はあるものの

基本の考え方はリソース単位ですね。

「要はバランスだよね」おじさん的

でしょうね。特定のクライアント向けという前提であれば。

メリデリ挙げてみて、両方のパターンの組み合わせを用意するのはどうなのだろうと思いつきました。

開発コストに問題がなければたくさん用意してあげたらいいでしょう。API利用するという事は相手も技術者なんだから、提供する側が方法を絞ってあげる必要はないですから。

加工までしてあげるんだったらそのまま表示箇所も作ってあげちゃった方が楽じゃないですか?客先向けのAPI仕様書を作る手間も省けて。

投稿2020/10/01 13:28

hentaiman

総合スコア6426

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

murabito

2020/10/01 23:46

> 面単位とリソース単位がかけ離れる状況ってなんですか? かけ離れるという訳ではないのですが、フロント側でリソースAの情報の一部と、リソースBの情報の一部をそれぞれ組み合わせて、加工、判断、計算をしないといけないような場面が出てきてしまうと思っています。 例えば、ログインユーザーのロールがXYZというロールで、かつ、帳票が生成済みの場合であれば、ダウンロードボタンを表示、または、活性化させたいような場合、ユーザーリソースに含まれるロール情報と、帳票情報に含まれるステータスの両方をみて、ダウンロード可能かどうかをフロント側で判断しないといけないみたいなケースです。
hentaiman

2020/10/02 03:28

その例だと、DL可能かどうかでボタンの表示非表示を切り替える点、DLボタンのリンク先を知られれば条件満たしてなくてもアクセスされてしまう点、いずれもSPAじゃなくても同じ事ですよね? 実際にDLを押された時の処理が有効か無効かはサーバー側で判定してレスポンス返すだけですよ。 条件を満たしていなければエラーを返せばいいんです。 示してくれた例だと↑の内容で済んでしまうので悩みどころが分かりません
murabito

2020/10/02 04:52

なるほど、たしかに!実際はバック側で権限チェックしてDLできるかどうかは必ずみることになるので、上の自分のDLの話は、ビジネスロジックというよりかは、フロント側の表示に関するロジックになると捉えて、フロント側にロジックがあっても問題ないとする感じで良いですかね?
hentaiman

2020/10/02 12:25

そうです。逆に聞きたいのですが、この回答とコメントを見た上で何が問題だと感じますか?それを聞いた方が返事し易い気が。 APIサーバーは飽くまでも自身へのリクエストの正当性(APIへのアクセス権限やパラメーターなど、諸々のバリデーション)を検証し、問題無ければレスポンスを返すだけです。 問題があれば単純に400エラーでもいいし、APIの仕様を推察されない程度にレスポンスにエラーの理由を含めてもいいです。
guest

0

私の場合ですが画面単位とリソース単位の中間の設計にします。

もしくは、「要はバランスだよね」おじさん的な感じになるのでしょうか!?

やはりこうなると思います。

理由としては
・APIのコマンド数はできるだけ抑えたい
→コマンド数増大は管理リスクも増大する

・ただ1度のAPIコマンドで大量データが取得されるのは困る。
→セキュリティの面でも一度に取得させたくない
→明細結果などはpageなどで一定量で区切りさせ処理する

・また1度のAPIコマンドですべて処理されるのも困る。
エラー発生時の対応が難しくなるのと、コマンドコピーされた場合のリスクが高くなる。

・拡張性は残したい
→あまりまとめすぎると影響が大きくなるので分散しておきたい。

処理単位としては

単票形式画面(更新あり)
認証用API(共通)
メイン読込用API(1レコードのみ)
選択リスト読込用API(コンボボックスなどのリスト用共通)
更新時データ送信用API(あくまでデータの送信のみ)
更新用データDB登録用API(ビジネスロジックを与えDBに登録する)

明細形式画面(更新なし)
認証用API(共通)
メイン読込用API(複数行だがページ単位とし一度に取得できる件数を絞る)

質問者様がおっしゃられているように一部のビジネスロジックは
JS側でカバーしないといけませんがメインはサーバ側。
ただし一回で登録させるのではなく2回に分ける。
(2回に分けた方がセキュリティ上も開発上も楽になる)

メイン読込用APIは画面の種類分用意
画面に必要ない余計な項目の値を通信したくないのと
共用にすると変更時の影響度が高くなる。
(共通化はサーバ内処理でとすればよい)

自分が設計したときはこの様なコンセプトでした。

あと個人情報の管理の観点から通信上は暗号化で行いJS側で復号しないといけないのが
意外と手間でしたね。

こうやって書いてみると機能単位の設計なるという事でしょうか。

投稿2020/10/01 17:14

kuma_kuma_

総合スコア2506

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

murabito

2020/10/02 05:03

> 質問者様がおっしゃられているように一部のビジネスロジックは JS側でカバーしないといけませんが すみません。自分が質問するのもおかしいのですが、フロント側で持ちそうな一部のビジネスロジックにはどのようなものがありそうでしょうか?自分がいまいち良い具体例を出せずちょっと困ってしまいまして。。。
kuma_kuma_

2020/10/02 05:18

そうですね 例では 組織図の選択式で 支店「xxx支店」 部・課「yyy部」 担当者「Aさん」 と選択できる項目を変化させる とかはフロント側で制御となります。 また一部の入力規則もフロント側になるかと思います。 A商品 単価100円 個数0個 → フロント側でエラー判定(必須入力判定) A商品 単価100円 個数10000個 → サーバ側で個数の妥当性を確認する。 この時発注価格の合計計算および適正範囲かもサーバ側で行う。 > フロント側で持ちそうな一部のビジネスロジック となっていますが私的には「入力規則レベル」と思っています。 (それ以上をフロント側にもたすのはリスクがある。)
murabito

2020/10/02 05:55

ありがとうございます! > 発注価格の合計計算および適正範囲かもサーバ側で行う 合計値を画面上に表示する場合はフロント側で計算してひとまず合計値の表示はしてしまって良いでしょうか?ただし、発注のPostリクエストをなげるときはパラメーターに合計値を渡すのではなく、合計値を計算するために必要な情報を渡すみたいな感じになりますかね? それとも、合計値を画面上に表示する場合は、PostメソッドのAPIエンドポイントにリクエストを送る前に、バリデーションを行うリクエストを投げて、レスポンスで合計金額を返してもらって画面上に合計値を表示することになりますでしょうか? 前者のメリットはすぐに合計値を表示できるので、UX的な面で良いが、デメリットはフロントにも合計計算ロジックが散らばる。後者のメリットはその逆、といったかたちで、この辺はUXを重視するならば、前者を選ぶみたいなトレードオフとなりますか?
kuma_kuma_

2020/10/02 06:10 編集

画面表示自体はフロントでよいかと思います。 1. 合計の表示はフロント側でリアルタイムに更新 2. 「保存」ボタン等でAPIにコマンド送信しDBへの追加更新処理を働かします。 3. 再度サーバ側でも合計値を計算、これがエラーになった場合APIの応答で合計値エラーを返します。 4. API保存処理でエラーになったので画面上「合計値エラーです」と表示させます。(メッセージや赤枠表示等) APIでデータを流す際はできるだけ余計な値は入れないほうが良いです。 (合計などはAPIサーバ側とフロント側2箇所に分けて) 1つのほうが便利そうなのですが開発担当をAPIサーバ側とフロント側に分けた際 APIサーバ側が完成しないとフロント側が作業できなくなるので効率が悪いんです。 あとテスト自体もAPIサーバ側とフロント側別々で行えます。 セキュリティ上も余計な情報はできるだけ通信に載せたくないのも理由の一つです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問