📖 読了目安 約23分
この記事の目次

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でのテスト例

  1. メソッドを選択(GET/POST等)
  2. URLを入力
  3. ヘッダーを設定(Authorization等)
  4. Bodyを入力(POST/PUT等)
  5. Sendで実行
  6. レスポンスを確認

よくある疑問

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仕様書から実装するときのポイント

  1. リクエスト/レスポンスの型を一致させる:API仕様書の型とDTOの型を合わせる
  2. エラーコードを仕様通りに返す:テストでチェックされる
  3. HTTPステータスコードを正しく返す:201, 400, 404, 409などを使い分ける
  4. バリデーションエラーメッセージ:API仕様書のメッセージを使う

関連ドキュメント