API設計で最初に決めていること

masasann
masasann
6分
2,116字

はじめに(この記事でわかること)

API設計って、CRUDのエンドポイントを生やす作業だと思われがちですが、実務で痛い目を見るのは「仕様の揺れ」や「例外の扱い」「認可の穴」みたいな“設計の前提”が曖昧なまま進んだときです。
この記事では、私がAPIを作り始める前に 最初に固定していること をまとめます。

背景・前提条件

  • チーム開発(レビューあり・複数人が触る)
  • フロント/外部連携がある(= 契約としてのAPIになる)
  • 後から機能追加・改修が入る前提(= 初期の「楽」は後で高くつく)

課題・問題点

API設計の初手で曖昧だと、後からこうなりがちです。

  • エラー形式がバラバラでフロントが例外処理地獄
  • 認可の粒度が合わず、画面権限制御が崩れる
  • 更新系の「整合性」や「同時更新」が事故る
  • 仕様変更のたびにURLやレスポンスが揺れて、利用側が疲弊する

検討した選択肢

A. とりあえずCRUDを作ってから考える

  • 初速は出る
  • ただし後から「全部直す」が発生しやすい(契約を変えるのは辛い)

B. 最初に“契約のコア”だけ決める

  • 最初は少し遅い
  • でも後からの変更が局所化しやすい(実務ではこっちが勝つことが多い印象)

このブログではBを推します。理由はシンプルで、APIは利用側が増えるほど変更コストが指数的に増えるからです。

採用した設計・実装(最初に決める項目)

1) リソースの境界(何が主語か)

  • 「何を1つのリソースとして扱うか」を先に定義します
    例:reservations の中に participants を持たせるのか、別リソースにするのか、など。

ここが曖昧だと、URLもレスポンスも泥団子になります。

2) 命名規則(URL / フィールド / ステータス)

  • URLは複数形で統一するか(/events
  • フィールドは snake_case / camelCase どちらか
  • 列挙値の表現(status: "draft" | "published" など)

「好み」っぽく見えるところですが、統一が壊れると利用側の認知負荷が増えます。

3) ページング・ソート・フィルタの基本形

CRUDだけ作っても、実務はすぐ「一覧」が重くなります。

  • page / per_page か、offset / limit
  • sort=created_at:desc のように複合ソートを許可するか
  • フィルタの表現(?status=published&category=backend

一覧APIの“型”を先に揃えると、後からの追加が楽になります。

4) エラーの形式(フロントが一番困るところ)

最低限、これだけは固定します。

  • code(機械判定用)
  • message(人間向け)
  • details(入力エラーのフィールド単位)

「毎回HTTPステータスだけ見ればいい」は現場では崩れやすいので、アプリケーションエラーの規約を持つのが安全です。

5) 認証・認可の入口(どこで担保するか)

  • 認証:誰か(トークン/セッション)
  • 認可:何ができるか(画面権限・ロール・スコープ)

API設計の最初にここを決めないと、後から「このエンドポイントだけ例外」が増えます。
私は「依存(ミドルウェア/DI)で必ず通す」など、通過点を固定するようにします。

6) 変更系の設計(PUT/PATCH/部分更新/状態遷移)

更新系は事故ポイントです。

  • PUT(全置換)か PATCH(部分更新)か
  • 状態遷移は「更新」でやるか「アクションAPI」にするか

ここはCRUDの延長に見えて、後から必ず揉めます。

7) 冪等性と同時更新(競合が起きる前提)

  • 冪等キー(決済/予約などで二重実行が致命的な時)
  • 楽観ロック(version / updated_at による競合検知)

「後で入れよう」はたいてい後で入れられません(契約が変わるので)。

実装例(雰囲気)

エラー形式を固定するだけでも、利用側はかなり楽になります。

  • 入力エラーは details にフィールド単位で詰める
  • ドメインエラーは code で分類する

実務での注意点・落とし穴

  • 最初に決めるのは「全部」じゃなくていい
    ただし 契約が揺れるところ(一覧/エラー/認可/更新) は先に固定したいです。
  • “使う側”の実装コストを観察する
    APIは作って終わりではなく、使われて初めて完成します。

まとめ

API設計の初手はCRUDよりも、揺れやすい契約(一覧・エラー・認可・更新)を固定するのが効きます。
ここが固まると、後から機能が増えても「同じ型で増やす」だけになります。

Written by