Prompt
バックエンドAPIはフロントエンドの視点を優先して設計すべきか?
バックエンドAPIのボイラープレートを減らす手段はどんなのが挙げられる?
バックエンドとフロントエンドの境界線に立つ設計思想は、まさに「スイスチーズモデル」の各層をどう密着させるかという議論だね。君が大切にしている「一意性」と「無駄の排除」という観点から、この2つの問いを解剖していこう。
1. バックエンドAPIはフロントエンドの視点を優先すべきか?
結論から言うと、「インターフェース(API)はフロントエンドの利便性を優先し、コアロジックはドメインの正しさを優先する」 という二層構造が理想的だよ。
かつては「DBの構造をそのままAPIにする」のが主流だったけれど、現代では以下の理由から 「フロントエンド(消費者)視点」 の設計が強く推奨されているんだ。
なぜフロントエンド優先(BFF思想)なのか
-
オーバーフェッチ / アンダーフェッチの防止: フロントが必要なデータだけを一度のリクエストで返さないと、モバイル環境などでパフォーマンスの「穴」になる。
-
画面の変化に強い: DBの正規化された構造に縛られすぎると、UIが少し変わるたびにフロントエンドで複雑なデータ加工が必要になり、属人性の高いロジックがフロントに漏れ出す。
ただし、バックエンドが守るべき「一意な真実」
フロントエンドに寄り添いすぎると、バックエンドが「UI専用の便利ツール」に成り下がってしまう。
-
ドメインロジックの死守: 「18歳未満は購入不可」といったビジネスルールは、UIがどうあれバックエンドが一意に保証しなければならない。
-
解決策: BFF (Backend For Frontend) パターンを採用する。
-
Core API: DBやドメインに忠実な、純粋で厳格なAPI。
-
BFF: 特定の画面(WebやiOS)に合わせてデータを整形する、フロントエンド専用の薄い層。
-
2. APIのボイラープレートを減らす手段
「二回書くのは無駄」という君の哲学に最も合致する、ボイラープレート(定型文)撲滅のための手段を 3 つ提案するよ。
① スキーマ駆動開発 (Schema-First)
OpenAPI (Swagger) や TypeSpec を使い、「API定義書」を唯一の正解(SSOT) とする。
-
手段: 定義書から、サーバー側のハンドラ、クライアント側のSDK(TypeScriptの型付き fetch)、さらにはモックサーバーまで自動生成する。
-
効果: 自分でボイラープレートを書く必要がなくなり、定義と実装の乖離という「属人性」を排除できる。
② tRPC や Connect (Buf)
プロトコルレベルでフロントとバックを結合し、APIエンドポイントという概念そのものを抽象化する。
-
tRPC: TypeScriptの型推論をそのまま通信に使う。サーバーの関数を書き換えれば、フロントの引数の型が自動的に変わり、コンパイルエラーで通知される。
-
Connect: gRPCをWebでも扱いやすくしたもので、
.protoファイルから各言語のボイラープレートを全自動生成する。
③ 高度なメタプログラミング (Rust特有の手段)
君が Rust を使うなら、マクロを活用したフレームワーク選びが重要だ。
-
Axum / Poem: 型安全なリクエスト抽出(Extractors)により、
serdeを通じて JSON のパースやバリデーションを数行で完結させる。 -
utoipa: Rust の構造体にアトリビュートを付けるだけで、OpenAPI 定義を自動生成する。
見落とされがちな視点:自動生成コードの「管理」
ボイラープレートを減らすためにコードを自動生成する場合、そのコードを 「Git で管理すべきか、ビルド時にのみ生成すべきか」 という新たな問いが生まれる。
-
Git 管理する: 依存関係が見えやすいが、手動で書き換えられる「魔改造」のリスクがある。
-
ビルド時に生成する: 常に最新の定義に強制同期されるが、CI の設定が少し複雑になる。
君のような「一意な正しさ」を求めるなら、「ビルド時に生成し、手動修正を一切許さない」 構成の方が、長期的にはスイスチーズの穴を塞ぐことになるはずだ。
結論
-
設計: インターフェースは「フロントの使いやすさ」、中身は「ドメインの厳格さ」で役割を分ける。
-
効率: 自分で書くのをやめ、「スキーマ」という設計図からプログラムを生成させる 仕組みを構築する。
次は、「実際に Rust (Axum) で OpenAPI 定義を自動生成し、そこから TypeScript の Zod スキーマを生成する具体的な CI パイプライン」 を作ってみる?
Would you like me to code a sample build.rs or a GitHub Action that automates this schema synchronization?