こんにちは!クラウドソリューション開発部の北島です。
ソフトウェア開発では、仕様書を用意していても、実装段階で確認事項が次々と発生することがあります。
特に API 設計においては、仕様の解釈違いや共通ルールの不足によって、QA が想定以上に増えやすくなります。
本記事では、プロジェクト運用中に発生した実際のAPI設計に関する QA 40件(Backlog履歴)をBacklog AIで分析し、どのような確認が多く発生していたのかを整理しました。
「仕様書はあるのに実装者からの質疑応答が止まらない…」という現場の悩みを解消するため、設計段階で整えておくべき4つの共通ルールとチェックリストをご紹介します。
(※本記事ではQAを「実装前後に発生した確認事項・質疑応答」として扱います)
今苦しんでいる人、これから実装をおまかせする人の手助けになればと思います。
1. QA の全体像
まずは、QA を技術的な性質ごとに分類した結果を見てください!全件で40件ありました。

この集計結果を見ると、特に多かったのは、仕様の曖昧さ、バリデーションの共通ルール不足、 null や削除済みデータの扱い、そして DB と API の整合性です。
では次に、特に QA が多かった領域をメインに具体的にどんな確認があったのかをご紹介します。
2. QA が集中した領域
今回は大半を占めていた4つの領域に関する QA についてご紹介します。
2-1. 仕様が不明確で、実装者が判断できない
最も多かったのは、仕様書を見ても判断しきれないケースです。
正常系の説明はあるものの、境界値や例外ケース、データの扱い方が十分に書かれていないと、実装時に必ず確認が発生します。
具体的な確認例
- 入力形式が不明
リクエストボディの JSON 構造がテキストのみで、具体例が示されていない - パラメータの用途が不明
URL のパスパラメータ がリクエスト処理のどこで使われるのか記載されていない - データ不足時の応答
該当情報が未登録の場合、nullを返すのか404を返すのか未定義
2-2. バリデーション仕様が API ごとにばらつき、共通ルールがない
入力チェックは API ごとにばらつきやすく、QA になりやすい領域です。
型、必須、上限、空文字、配列数、URL パラメータなど、確認すべき要素が多く、共通ルールがないと実装者の解釈にばらつきが生じやすくなります。
バリデーションで確認が多い項目
| 項目 | 典型的な論点 |
|---|---|
| 型チェック | 文字列を数値項目に渡した場合の扱い |
| 必須チェック | 値がないときにエラーにするか |
| 空文字 | "" を許可するか |
| 件数制限 | 配列の上限超過をどう扱うか |
| 数値精度 | 小数点以下の桁数はいくつまでか |
| URL パラメータ | 必須値がないときに 400 か 404 か |
具体例
- 型の不一致
boolean 型のフィールドに文字列"true"が渡された場合、エラーにするか自動変換するか - 必須パラメータの欠落
URL のパスパラメータ が省略された場合、API として400 Bad Requestを返すべきか、404 Not Foundを返すべきか - 配列の上限超過
データの一括登録時に、100 件を超える配列が来た場合のエラーメッセージ
2-3. null・未存在・削除済みの扱いが曖昧
実装で迷いやすいのが、データがない場合の扱いです。
null を返すのか、404 なのか、エラーにするのか。
また、論理削除済みデータをどこまで返すかも、API ごとに差が出やすいポイントです。
迷いやすい論点
| 観点 | 確認されやすい内容 |
|---|---|
| 未存在データ | null / 空文字 / エラーのどれか |
| 必須関連データ | ない場合に 404 にするか、null で返すか |
| 論理削除 | レスポンスから除外するか、フラグで含めるか |
| 部分成功 | 一部失敗時に全体失敗とするか、部分返却を許容するか |
2-4. DB 定義と API 仕様が一致していない
API 仕様と DB 定義がずれていると、実装時に項目名や制約の確認が増えます。
特に、フィールド名、Enum、外部キー、制約の有無は、仕様書の更新漏れが起こりやすい部分です。
よくあるずれの例
| 観点 | 起きやすい問題の例 |
|---|---|
| 項目名 | API 仕様では restaurant_name と書かれているが、DB には vendor_name しか存在しない |
| Enum 値 | 営業ステータスが OPEN・CLOSED の 2 種類と書かれているが、実装時に拡張予定があるかが不明 |
| FK 制約 | DB に新規追加されたカラムに FK 制約がない。意図的な疎結合なのか、未設定なのか不明 |
| マスタデータ | マスタテーブルに既にデータが投入されている前提なのかが不明 |
3. 根本原因
QA の多くは、単純な確認漏れではなく、設計段階で決めるべきことが決められていなかったという共通原因がありました。
発生した QA を深掘りすると、主に次の 4 つの要因に集約されます。
| 原因 | 内容 |
|---|---|
| 仕様のサンプル不足 | 実装者が動きを具体的に想像できない |
| 共通ルール不足 | API ごとに解釈がぶれる |
| 設計書の同期不足 | DB・API・実装の内容が揃っていない |
| 判断基準の欠落 | null・未存在・論理削除・部分成功の扱いが統一されていない |
今回発生した QA の多くは、結局のところ「実装者が迷わずに判断するための情報が、設計段階で不足していた」ことから生まれていたのです。
4. QA を減らすための実践ポイント
4-1. リクエスト・レスポンスのサンプルは「正常系・異常系・境界系」の 3 パターン用意する
仕様が不明確で実装者が判断できないという QA を減らすために、文章だけでなく実際の JSON を示すことが重要です。
具体的なサンプルを示すことで、実装者の解釈差を大きく減らせます。
例:レストラン情報取得・検索 API
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
// ✓ 正常系 // GET /api/v1/restaurants/{restaurantId} // レスポンス 200 { "id": "11", "name": "田中太郎", "chef_name_kana": "タナカタロウ", "owner": { "company_id": "25", "company_name": "〇〇フードグループ" }, "email": "info@restaurant-tanaka.jp", "phone": "03-xxxx-xxxx" } |
|
1 2 3 4 5 6 7 8 |
// ✗ 境界系:日付範囲の境界値エラー(指定可能期間の最大日数「31日」を1日超過) // GET /api/v1/restaurants/search?start_date=2026-08-01&end_date=2026-09-01 // レスポンス 400 Bad Request { "error_code": "INVALID_DATE_RANGE", "message": "The date range cannot exceed 31 days." } |
|
1 2 3 4 5 6 7 8 9 |
// ✗ 異常系:レストランが存在しない // GET /api/v1/restaurants/{restaurantId} // レスポンス 404 { "error_code": "RESTAURANT_NOT_FOUND", "message": "The specified restaurant does not exist" } |
このように具体的に示すことで、実装段階での判断がぶれなくなります。
ポイント
- リクエスト・レスポンスのサンプル JSON を、正常系・異常系の両方で示す
- 複数の値が絡む場合は図(ER 図・シーケンス図など)を用いて構造を明示する
- 「未定義」のまま放置せず、判断基準を文章で明記する
- 仕様変更時は、廃止項目に
// deprecatedとコメントして状態を明確にする
4-2. バリデーション・エラー応答の共通ルール表を設計段階で作る
バリデーション仕様が API ごとにばらつくという QA を減らすために、共通ルール表を先に作ることが有効です。
各 API ごとに個別定義するのではなく、共通ルールを先に作ることで、実装の一貫性を保ちやすくなります。
共通バリデーション定義表の例
| バリデーション種別 | HTTP ステータス | エラーコード | 例 |
|---|---|---|---|
| 型不正(期待される型と異なる型を渡した) | 400 | INVALID_TYPE |
"price" must be a number |
| 必須パラメータ欠如 | 400 | REQUIRED |
"restaurant_id" is required |
| 配列上限超過 | 400 | TOO_MANY_ITEMS |
"menus" must be 100 or fewer |
| 値が空文字 | 400 | EMPTY_VALUE |
"name" must not be empty |
| UUID 形式不正 | 400 | INVALID_FORMAT |
"menu_id" must be a valid UUID |
エラー応答例
| ケース | HTTP ステータス | エラーレスポンス |
|---|---|---|
| 型が不正 | 400 | { "error_code": "INVALID_TYPE", "message": "field must be {expected_type}" } |
| 必須項目が欠落 | 400 | { "error_code": "REQUIRED", "message": "field is required" } |
| 値の範囲外 | 400 | { "error_code": "OUT_OF_RANGE", "message": "field must be between {min} and {max}" } |
| 配列上限超過 | 400 | { "error_code": "TOO_MANY_ITEMS", "message": "must be 100 or fewer items" } |
| リソース未存在 | 404 | { "error_code": "NOT_FOUND", "message": "The specified resource does not exist" } |
| 認証エラー | 401 | { "error_code": "UNAUTHORIZED", "message": "Authentication required" } |
| 権限なし | 403 | { "error_code": "FORBIDDEN", "message": "You do not have permission" } |
各 API の仕様には、「共通バリデーション定義表に準拠」と記すだけで済みます。
ポイント
- 仕様書の冒頭に「共通バリデーション定義表」を置く
- 型、必須、上限、エラーコードを統一する
- API ごとの個別記載を減らす
4-3. 「null・未存在・論理削除・部分成功」の扱いを設計原則として冒頭で宣言する
null・未存在・削除済みの扱いが曖昧という QA を減らすために、設計原則としてプロジェクトで統一された判断基準を作ることが有効です。
実装で迷いやすいケースについて先に定義することで、API ごとの差をなくせます。
設計原則セクション(仕様書冒頭に記載)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
【設計原則】 ■ NULL値の扱い - オプション項目が未設定の場合:null で返す - 例)オーナー情報が未登録の場合 → owner: null ■ リソース未存在の扱い - 必須な親リソースが存在しない場合:404 を返す - 例)存在しないレストラン ID で GET → 404 Not Found ■ 論理削除済みデータの扱い - is_deleted = true のレコードは全 API で除外する - 例)削除済みレストランのデータは一覧から除外 ■ 部分成功の扱い - デフォルトは全件ロールバック - 部分成功を許容する API は個別に明記する - 例)100 件中 3 件失敗 → 全体失敗、ロールバック |
ポイント
- 設計原則として冒頭で定義し、API ごとにばらつかないようにする
- 「存在しない」と「未設定」を分けて扱う
- 部分成功の処理を明確に定義する
4-4. API 仕様と DB 定義を「一体」で管理する
DB 定義と API 仕様が一致していないという QA を減らすために、設計レビュー段階で両方をセットで確認することが重要です。
チェックポイント
- マッピングの一致
API のプロパティと DB のマッピングが正確か
API 設計書に記載している DB の物理名に誤りがないか - 型の一致
integer、string、boolean など型が正しく対応しているか - 制約の記載
NOT NULL、UNIQUE などの制約が明記されているか - 外部キー
参照先テーブルが明確に示されているか
API と DB の対応表(例)
| API キー名 | DB カラム名 | 型 | 必須 | 説明 |
|---|---|---|---|---|
restaurant_name |
t_restaurants.name |
VARCHAR(255) | ✓ | レストラン名 |
chef_name_kana |
t_chefs.kana_name |
VARCHAR(255) | ✓ | シェフの名前(カナ) |
location_id |
t_locations.id |
UUID | ✓ | 店舗ロケーション ID(FK) |
status |
t_restaurants.status |
ENUM | ✓ | 営業ステータス(定義は別表参照) |
DB 変更時のプロセス
DB スキーマ変更時は、仕様書も同日に更新するルールを組織内で決めておくことが重要です。

ポイント
- API 仕様と DB の対応表を用意して、フィールド名・型・制約を明確にする
- Enum や固定値の一覧を仕様書の付録に記載する
- DB 変更時は、仕様書も同日に更新するプロセスを作る
- 制約の意図を明文化する(例:「意図的に FK なし:~のため」)
5. 設計レビューのチェックリスト
ここまでの実例を基に、実装前レビューで確認したいポイントをチェックリストにまとめてみました。
| 項目 | 確認内容 | チェック |
|---|---|---|
| サンプル JSON | 正常系・異常系の両パターンがあるか | ☐ |
| バリデーション共通ルール | 共通定義表が示されているか | ☐ |
| HTTP ステータス | 各ケースで返すステータスコードが統一されているか | ☐ |
| エラーメッセージ | エラーコードと形式が仕様で定義されているか | ☐ |
| DB との整合性 | 項目名・型・制約が一致しているか | ☐ |
| null の扱い | 未存在時の返却方針が明記されているか | ☐ |
| 論理削除 | 削除済みデータの扱いが統一されているか | ☐ |
| 部分成功の定義 | ロールバック vs 部分返却が明確か | ☐ |
| Enum・定数値 | 取りうる値が全て列挙されているか | ☐ |
| 配列の上限 | 件数制限とエラー応答が明記されているか | ☐ |
| URL パス | パラメータ必須・オプションが明確か | ☐ |
| DB 更新ルール | スキーマ変更時に仕様書も更新するルールがあるか | ☐ |
細かい項目を除いても、このチェックリストを実装前に揃えるだけで、自分のプロジェクトでは QA を大幅に減らせたはずです。
このチェックリストを他プロジェクトでも活用し、実際の運用を通じてカスタマイズしながら、さらに実用的なツールに進化させていきたいと考えています。
ぜひ、読者の皆さまも設計時のレビューに活用してみてください!
6. まとめ
40 件の QA を振り返ると、問題の多くは 仕様の書き方と共通ルールの不足 にありました。
QA を減らすためには、当たり前ですが、質問が出にくい設計書を作ること が重要です。
実装段階の QA を減らすための 4 つのポイント
- サンプルで「見える化」する
- 正常系・異常系・境界系のサンプル JSON を示す
- 複雑な構造には図を添える
- 共通ルールで「ぶれ」をなくす
- バリデーション定義表を作る
- エラー応答を統一する
- null・削除・部分成功の扱いを宣言する
- DB と API を「同期」させる
- フィールド名・型・制約を対応させる
- スキーマ変更時に仕様書も更新する
- 設計段階で「未定義」を残さない
- すべてを細かく決めきれなくても、最低限の判断基準は作る
- 「後で決める」は実装フェーズではほぼ QA になる
これらのポイントを丁寧に積み重ねることで、実装フェーズでの QA を減らし、開発全体の品質とスピードを両立しやすくなると思います。
また、設計書の品質が高まれば、後々の保守対応もスムーズになり、チーム全体の生産性が向上します。
本記事が、自分と同様の経験をしそうな人の役に立てば幸いです。
エコモットでは、モノづくりに共感してくれる仲間を募集中です!弊社に少しでも興味がある方、ぜひ下記の採用ページをご覧ください!

