この記事の目次
API仕様書の読み方
API仕様書は、APIのエンドポイント、リクエスト、レスポンスを定義したドキュメントです。フロントエンドとバックエンドの連携で必ず参照します。
API仕様書とは
役割
- エンドポイント(URL)を定義
- HTTPメソッド(GET/POST等)を定義
- リクエスト(送るデータ)を定義
- レスポンス(返ってくるデータ)を定義
- エラー(異常時の応答)を定義
いつ使うか
| 場面 | 使い方 |
|---|---|
| フロントエンド実装時 | API呼び出しの実装 |
| バックエンド実装時 | API実装の指針 |
| テスト時 | APIの動作確認 |
| 障害調査時 | リクエスト/レスポンスの確認 |
API仕様書の構成
よくある構成要素
| 項目 | 内容 | 確認ポイント |
|---|---|---|
| エンドポイント | APIのURL | パス、パラメータ |
| メソッド | HTTP動詞 | GET/POST/PUT/DELETE |
| ヘッダー | リクエストヘッダー | 認証、Content-Type |
| リクエストボディ | 送信するデータ | 型、必須/任意 |
| レスポンス | 返却されるデータ | 型、構造 |
| ステータスコード | HTTPステータス | 成功/エラー時 |
HTTPメソッドの使い分け
| メソッド | 用途 | 例 |
|---|---|---|
| GET | データ取得 | ユーザー情報取得 |
| POST | データ作成 | 新規登録 |
| PUT | データ更新(全体) | ユーザー情報更新 |
| PATCH | データ更新(一部) | パスワード変更 |
| DELETE | データ削除 | アカウント削除 |
【サンプル】API仕様書の実例
ユーザー管理APIの仕様書
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
API仕様書
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
■ 基本情報
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
ベースURL : https://api.example.com/v1
認証方式 : Bearer Token
Content-Type : application/json
バージョン : v1.0
API-001:ユーザー登録
■ 概要
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
新規ユーザーを登録する
■ エンドポイント
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
POST /users
■ 認証
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
不要
■ リクエストヘッダー
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
| ヘッダー | 値 | 必須 |
|----------|-----|------|
| Content-Type | application/json | ○ |
■ リクエストボディ
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
| パラメータ | 型 | 必須 | 説明 | 制約 |
|-----------|------|------|------|------|
| email | string | ○ | メールアドレス | メール形式、256文字以内 |
| password | string | ○ | パスワード | 8文字以上、英数字混合 |
| name | string | ○ | 氏名 | 100文字以内 |
| phone | string | - | 電話番号 | ハイフン含む15文字以内 |
【リクエスト例】
{
"email": "user@example.com",
"password": "Password123",
"name": "山田太郎",
"phone": "03-1234-5678"
}
■ レスポンス
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
【成功時】201 Created
| パラメータ | 型 | 説明 |
|-----------|------|------|
| id | integer | ユーザーID |
| email | string | メールアドレス |
| name | string | 氏名 |
| created_at | string | 作成日時(ISO8601) |
{
"id": 12345,
"email": "user@example.com",
"name": "山田太郎",
"created_at": "2024-01-15T10:30:00+09:00"
}
■ エラーレスポンス
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
| ステータス | エラーコード | 説明 |
|-----------|-------------|------|
| 400 | INVALID_REQUEST | リクエスト形式エラー |
| 400 | INVALID_EMAIL | メール形式エラー |
| 400 | INVALID_PASSWORD | パスワード形式エラー |
| 409 | EMAIL_EXISTS | メールアドレス重複 |
| 500 | INTERNAL_ERROR | システムエラー |
{
"error": {
"code": "EMAIL_EXISTS",
"message": "このメールアドレスは既に登録されています"
}
}
API-002:ユーザー情報取得
■ 概要
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
指定したユーザーの情報を取得する
■ エンドポイント
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
GET /users/{id}
■ パスパラメータ
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
| パラメータ | 型 | 説明 |
|-----------|------|------|
| id | integer | ユーザーID |
■ 認証
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
必要
■ リクエストヘッダー
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
| ヘッダー | 値 | 必須 |
|----------|-----|------|
| Authorization | Bearer {token} | ○ |
■ レスポンス
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
【成功時】200 OK
{
"id": 12345,
"email": "user@example.com",
"name": "山田太郎",
"phone": "03-1234-5678",
"created_at": "2024-01-15T10:30:00+09:00",
"updated_at": "2024-02-01T15:00:00+09:00"
}
■ エラーレスポンス
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
| ステータス | エラーコード | 説明 |
|-----------|-------------|------|
| 401 | UNAUTHORIZED | 認証エラー |
| 403 | FORBIDDEN | 権限エラー |
| 404 | NOT_FOUND | ユーザーが存在しない |
API-003:ユーザー一覧取得
■ 概要
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
ユーザー一覧を取得する(ページング対応)
■ エンドポイント
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
GET /users
■ クエリパラメータ
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
| パラメータ | 型 | 必須 | 説明 | デフォルト |
|-----------|------|------|------|-----------|
| page | integer | - | ページ番号 | 1 |
| per_page | integer | - | 1ページあたりの件数 | 20 |
| sort | string | - | ソート項目 | created_at |
| order | string | - | ソート順(asc/desc) | desc |
■ リクエスト例
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
GET /users?page=2&per_page=10&sort=name&order=asc
■ レスポンス
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
【成功時】200 OK
{
"data": [
{
"id": 12345,
"email": "user1@example.com",
"name": "田中太郎"
},
{
"id": 12346,
"email": "user2@example.com",
"name": "鈴木花子"
}
],
"pagination": {
"total": 100,
"per_page": 10,
"current_page": 2,
"total_pages": 10
}
}
HTTPステータスコードの意味
| コード | 意味 | 使用場面 |
|---|---|---|
| 200 | OK | 成功(取得、更新) |
| 201 | Created | 成功(作成) |
| 204 | No Content | 成功(削除、レスポンスなし) |
| 400 | Bad Request | リクエスト形式エラー |
| 401 | Unauthorized | 認証エラー |
| 403 | Forbidden | 権限エラー |
| 404 | Not Found | リソースが存在しない |
| 409 | Conflict | 競合エラー(重複など) |
| 422 | Unprocessable Entity | バリデーションエラー |
| 500 | Internal Server Error | サーバーエラー |
API仕様書を読むときのポイント
1. エンドポイントを確認する
- ベースURLは何か
- パスはどうなっているか
- パスパラメータはあるか
2. リクエストを確認する
- 必須パラメータは何か
- 型は何か(string/integer/boolean)
- 制約は何か(文字数、形式)
3. レスポンスを確認する
- どんなデータが返ってくるか
- ネストした構造はどうなっているか
- 配列かオブジェクトか
4. エラーを確認する
- どんなエラーが返ってくるか
- エラーコードは何か
- エラーメッセージはどこにあるか
APIテストツールの活用
| ツール | 特徴 |
|---|---|
| Postman | GUIで簡単にテスト |
| cURL | コマンドラインで実行 |
| Insomnia | シンプルなUI |
| ブラウザ開発者ツール | 実際の通信を確認 |
Postmanでのテスト例
- メソッドを選択(GET/POST等)
- URLを入力
- ヘッダーを設定(Authorization等)
- Bodyを入力(POST/PUT等)
- Sendで実行
- レスポンスを確認
よくある疑問
Q: 認証トークンはどこで取得する?
ログインAPIで取得することが多いです。仕様書の認証の章を確認しましょう。
Q: レスポンスの日時形式は?
ISO8601形式(2024-01-15T10:30:00+09:00)が一般的です。タイムゾーンにも注意。
Q: エラー時のハンドリングは?
ステータスコードとエラーコードを確認し、適切にハンドリングします。
【実践】API仕様書からSpring Bootで実装する
サンプルのユーザー登録API仕様書から、Spring Bootで実装してみましょう。
ステップ1:リクエストDTOを作る
API仕様書の「リクエストボディ」からDTOクラスを作成します。
import javax.validation.constraints.*;
// API仕様書の「リクエストボディ」から作成
public class UserRegistrationRequest {
// email - string, 必須, メール形式、256文字以内
@NotBlank(message = "メールアドレスを入力してください")
@Email(message = "メールアドレスの形式が正しくありません")
@Size(max = 256)
private String email;
// password - string, 必須, 8文字以上
@NotBlank(message = "パスワードを入力してください")
@Size(min = 8, max = 64, message = "パスワードは8文字以上で入力してください")
private String password;
// name - string, 必須, 100文字以内
@NotBlank(message = "氏名を入力してください")
@Size(max = 100)
private String name;
// phone - string, 任意, ハイフン含む15文字以内
@Size(max = 15)
private String phone;
// getter/setter は省略
}
ステップ2:レスポンスDTOを作る
API仕様書の「レスポンス」からDTOクラスを作成します。
import java.time.LocalDateTime;
// API仕様書の「レスポンス(成功時)」から作成
public class UserRegistrationResponse {
private Long id;
private String email;
private String name;
private LocalDateTime createdAt;
// コンストラクタ
public UserRegistrationResponse(User user) {
this.id = user.getId();
this.email = user.getEmail();
this.name = user.getName();
this.createdAt = user.getCreatedAt();
}
// getter は省略
}
ステップ3:エラーレスポンスを作る
API仕様書の「エラーレスポンス」からエラー用のクラスを作成します。
// エラーレスポンスの構造
public class ApiError {
private ErrorDetail error;
public ApiError(String code, String message) {
this.error = new ErrorDetail(code, message);
}
// getter
public ErrorDetail getError() { return error; }
// 内部クラス
public static class ErrorDetail {
private String code;
private String message;
public ErrorDetail(String code, String message) {
this.code = code;
this.message = message;
}
// getter
}
}
// エラーコードをEnumで管理
public enum ErrorCode {
INVALID_REQUEST("リクエスト形式が不正です"),
INVALID_EMAIL("メールアドレスの形式が正しくありません"),
INVALID_PASSWORD("パスワードの形式が正しくありません"),
EMAIL_EXISTS("このメールアドレスは既に登録されています"),
INTERNAL_ERROR("システムエラーが発生しました");
private final String message;
ErrorCode(String message) {
this.message = message;
}
public String getMessage() { return message; }
}
ステップ4:コントローラーを作る
API仕様書の「エンドポイント」と「メソッド」からコントローラーを作成します。
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
@RestController
@RequestMapping("/api/v1") // ベースURL
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
// POST /users - ユーザー登録
@PostMapping("/users")
public ResponseEntity<?> registerUser(
@Valid @RequestBody UserRegistrationRequest request) {
try {
User user = userService.register(request);
// 成功時: 201 Created
return ResponseEntity
.status(HttpStatus.CREATED)
.body(new UserRegistrationResponse(user));
} catch (EmailAlreadyExistsException e) {
// 409 Conflict: メールアドレス重複
return ResponseEntity
.status(HttpStatus.CONFLICT)
.body(new ApiError("EMAIL_EXISTS", e.getMessage()));
}
}
// GET /users/{id} - ユーザー情報取得
@GetMapping("/users/{id}")
public ResponseEntity<?> getUser(@PathVariable Long id) {
return userService.findById(id)
.map(user -> ResponseEntity.ok(new UserResponse(user)))
.orElse(ResponseEntity.notFound().build()); // 404
}
// GET /users - ユーザー一覧取得(ページング対応)
@GetMapping("/users")
public ResponseEntity<PagedResponse<UserResponse>> getUsers(
@RequestParam(defaultValue = "1") int page,
@RequestParam(defaultValue = "20") int perPage,
@RequestParam(defaultValue = "created_at") String sort,
@RequestParam(defaultValue = "desc") String order) {
Page<User> users = userService.findAll(page, perPage, sort, order);
return ResponseEntity.ok(new PagedResponse<>(users));
}
}
ステップ5:バリデーションエラーのハンドリング
Spring Bootの@Validアノテーションによるバリデーションエラーを処理します。
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class GlobalExceptionHandler {
// バリデーションエラー → 400 Bad Request
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ApiError> handleValidationError(
MethodArgumentNotValidException ex) {
String message = ex.getBindingResult()
.getFieldErrors()
.stream()
.findFirst()
.map(error -> error.getDefaultMessage())
.orElse("入力エラー");
return ResponseEntity
.badRequest()
.body(new ApiError("INVALID_REQUEST", message));
}
// その他の例外 → 500 Internal Server Error
@ExceptionHandler(Exception.class)
public ResponseEntity<ApiError> handleInternalError(Exception ex) {
return ResponseEntity
.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ApiError("INTERNAL_ERROR", "システムエラーが発生しました"));
}
}
API仕様書とコードの対応表
| API仕様書の項目 | 対応するコード |
|---|---|
| エンドポイント | @RequestMapping, @GetMapping, @PostMapping |
| リクエストボディ | リクエストDTO + @RequestBody |
| パスパラメータ | @PathVariable |
| クエリパラメータ | @RequestParam |
| レスポンス(成功) | レスポンスDTO + ResponseEntity.ok() |
| レスポンス(201) | ResponseEntity.status(HttpStatus.CREATED) |
| エラーレスポンス | @ExceptionHandler + ApiError |
| 認証 | Spring Security(別途設定) |
フロントエンドからのAPI呼び出し例
// ユーザー登録API呼び出し
async function registerUser(formData) {
try {
const response = await fetch('/api/v1/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(formData)
});
if (response.status === 201) {
// 成功
const data = await response.json();
console.log('登録成功:', data);
return { success: true, data };
} else {
// エラー
const error = await response.json();
console.log('エラー:', error.error.code, error.error.message);
return { success: false, error: error.error };
}
} catch (e) {
return { success: false, error: { code: 'NETWORK_ERROR', message: '通信エラー' } };
}
}
API仕様書から実装するときのポイント
- リクエスト/レスポンスの型を一致させる:API仕様書の型とDTOの型を合わせる
- エラーコードを仕様通りに返す:テストでチェックされる
- HTTPステータスコードを正しく返す:201, 400, 404, 409などを使い分ける
- バリデーションエラーメッセージ:API仕様書のメッセージを使う
関連ドキュメント
- 設計書・仕様書の読み方 - 設計書全般の読み方
- 詳細設計書の読み方 - 詳細設計書全般
- 処理設計書の読み方 - バックエンド処理の詳細
- テーブル定義書の読み方 - DBとの対応