第3部:ドキュメントスキル / 第6章:API連携

API仕様書の読み方

API仕様書は、APIのエンドポイント、リクエスト、レスポンスを定義したドキュメントです。フロントエンドとバックエンドの連携で必ず参照します。

📖 読了目安 約20分 対象: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のサンプル仕様書です。以下の基本情報から始まります。

ベースURLhttps://api.example.com/v1
認証方式Bearer Token
Content-Typeapplication/json
バージョンv1.0

API-001:ユーザー登録

概要:新規ユーザーを登録するAPI

エンドポイント:POST /users

認証:不要

リクエストヘッダー:

ヘッダー必須
Content-Typeapplication/json

リクエストボディ:

パラメータ必須説明制約
emailstringメールアドレスメール形式、256文字以内
passwordstringパスワード8文字以上、英数字混合
namestring氏名100文字以内
phonestring-電話番号ハイフン含む15文字以内

リクエスト例:

{
  "email": "user@example.com",
  "password": "Password123",
  "name": "山田太郎",
  "phone": "03-1234-5678"
}

レスポンス(成功時:201 Created):

パラメータ説明
idintegerユーザーID
emailstringメールアドレス
namestring氏名
created_atstring作成日時(ISO8601)
{
  "id": 12345,
  "email": "user@example.com",
  "name": "山田太郎",
  "created_at": "2024-01-15T10:30:00+09:00"
}

エラーレスポンス:

ステータスエラーコード説明
400INVALID_REQUESTリクエスト形式エラー
400INVALID_EMAILメール形式エラー
400INVALID_PASSWORDパスワード形式エラー
409EMAIL_EXISTSメールアドレス重複
500INTERNAL_ERRORシステムエラー
{
  "error": {
    "code": "EMAIL_EXISTS",
    "message": "このメールアドレスは既に登録されています"
  }
}

API-002:ユーザー情報取得

概要:指定したユーザーの情報を取得するAPI

エンドポイント:GET /users/{id}

パスパラメータ:

パラメータ説明
idintegerユーザーID

認証:必要

リクエストヘッダー:

ヘッダー必須
AuthorizationBearer {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"
}

エラーレスポンス:

ステータスエラーコード説明
401UNAUTHORIZED認証エラー
403FORBIDDEN権限エラー
404NOT_FOUNDユーザーが存在しない

API-003:ユーザー一覧取得

概要:ユーザー一覧を取得するAPI(ページング対応)

エンドポイント:GET /users

クエリパラメータ:

パラメータ必須説明デフォルト
pageinteger-ページ番号1
per_pageinteger-1ページあたりの件数20
sortstring-ソート項目created_at
orderstring-ソート順(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ステータスコードの意味

コード意味使用場面
200OK成功(取得、更新)
201Created成功(作成)
204No Content成功(削除、レスポンスなし)
400Bad Requestリクエスト形式エラー
401Unauthorized認証エラー
403Forbidden権限エラー
404Not Foundリソースが存在しない
409Conflict競合エラー(重複など)
422Unprocessable Entityバリデーションエラー
500Internal Server Errorサーバーエラー

API仕様書を読むときのポイント

1. エンドポイントを確認する

  • ベースURLは何か
  • パスはどうなっているか
  • パスパラメータはあるか

→ これを確認しないと、どのURLにリクエストを送ればよいか分かりません

2. リクエストを確認する

  • 必須パラメータは何か
  • 型は何か(string/integer/boolean)
  • 制約は何か(文字数、形式)

→ リクエストを間違えるとAPIはエラーを返します

3. レスポンスを確認する

  • どんなデータが返ってくるか
  • ネストした構造はどうなっているか
  • 配列かオブジェクトか

→ レスポンスの形を知らないと、返ってきたデータを処理できません

4. エラーを確認する

  • どんなエラーが返ってくるか
  • エラーコードは何か
  • エラーメッセージはどこにあるか

→ エラーハンドリングをしないと、予期しない動作が発生します

APIテストツールの活用

ツール特徴
PostmanGUIで簡単にテスト
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> getUsers(
            @RequestParam(defaultValue = "1") int page,
            @RequestParam(defaultValue = "20") int perPage,
            @RequestParam(defaultValue = "created_at") String sort,
            @RequestParam(defaultValue = "desc") String order) {

        Page 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 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 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仕様書のメッセージを使います

関連ドキュメント