🦔

# 3.6 レスポンス設計のベストプラクティス(Django REST Framework 編)

に公開

レスポンス設計のベストプラクティス(Django REST Framework 編)

前回の記事ではパフォーマンス改善と N+1 対策について紹介した。
今回は レスポンス設計のベストプラクティス をテーマにまとめる。

API のレスポンスはフロントエンドが直接扱う部分。
一貫性がなく使いにくい設計だと、結局フロント側の複雑さが増してしまう。
ここでは業務システムで実践しているポイントを整理する。


1. id は必須フィールド

どんな API でも id を返す ことを徹底する。
一覧でも詳細でも、更新やリンクに必要になるため。

{
  "id": 1,
  "customer_name": "株式会社テスト"
}

2. 一覧と詳細で返却項目を分ける

一覧 API は軽量に、詳細 API は情報を豊富に。

一覧 API(軽量)

[
  { "id": 1, "customer_name": "株式会社テスト", "total_amount": 50000 },
  { "id": 2, "customer_name": "サンプル商事", "total_amount": 120000 }
]

詳細 API(リッチ)

{
  "id": 1,
  "customer_name": "株式会社テスト",
  "total_amount": 50000,
  "created_at": "2024-04-01T10:00:00Z",
  "items": [
    { "id": 101, "product_name": "商品A", "quantity": 2, "price": 10000 },
    { "id": 102, "product_name": "商品B", "quantity": 1, "price": 30000 }
  ]
}

Serializer を分けて実装するのが一般的。


3. 表示用フィールドを追加する

金額や日付など、フロントでフォーマットしにくいデータは「表示用フィールド」を追加して返すと便利。

class OrderSerializer(serializers.ModelSerializer):
    total_amount_display = serializers.SerializerMethodField()
    created_at_display = serializers.SerializerMethodField()

    class Meta:
        model = Order
        fields = ["id", "customer_name", "total_amount", "total_amount_display", "created_at", "created_at_display"]

    def get_total_amount_display(self, obj):
        return f"¥{obj.total_amount:,}"

    def get_created_at_display(self, obj):
        return obj.created_at.strftime("%Y/%m/%d %H:%M")

レスポンス例:

{
  "id": 1,
  "customer_name": "株式会社テスト",
  "total_amount": 50000,
  "total_amount_display": "¥50,000",
  "created_at": "2024-04-01T10:00:00Z",
  "created_at_display": "2024/04/01 19:00"
}

4. ネスト構造の扱いを整理する

関連データをどう返すかは API 設計の肝。

  • 一覧 API → 関連データは ID のみにする(軽量化のため)
  • 詳細 API → ネストしたオブジェクトで返す(ユーザーが画面で必要とする情報をまとめる)

例: 一覧 API

{ "id": 1, "customer_id": 10, "customer_name": "株式会社テスト" }

例: 詳細 API

{
  "id": 1,
  "customer": {
    "id": 10,
    "name": "株式会社テスト",
    "address": "東京都千代田区1-1-1"
  }
}

5. ステータス表現の工夫

数値コードだけでなく、フロント表示用のラベルも一緒に返す。

{
  "status": "approved",
  "status_display": "承認済み"
}

こうすることで、フロントは翻訳辞書を持たなくてもそのまま表示できる。


6. 一貫性を保つルールを決める

  • 命名規則

    • スネークケースで統一 (customer_name, total_amount)
  • 日時は ISO 8601

    • "2024-04-01T10:00:00Z"
  • 金額は数値で返す(文字列にしない)


AI活用の観点

レスポンス設計も AI にサポートさせやすい領域。
ただし「おまかせ」だけでは意図通りにならないことが多いので、工夫が必要。

  • まずはおまかせで雛形を生成
    例えば「DRF で一覧と詳細でレスポンスを分ける実装例を」と依頼すれば、
    Serializer を分けた基本形をすぐに出してくれる。

  • 既存レスポンスを例示して整形を依頼
    「この JSON をベースに、status にラベルを追加して」と伝えると、
    status_display を追加した Serializer を提案してくれる。

  • 命名規則やフォーマットを守らせる
    AI は camelCasesnake_case を混在させることもある。
    「すべて snake_case で」と明示することで一貫性を担保できる。

  • 表示用フィールドの追加は AI に任せやすい
    金額フォーマットや日付整形などは「display 用フィールドを追加して」と言えば即座にコードが生成される。
    ただし「どのフィールドを追加するか」の判断は人間側の設計が必要。

  • ネスト構造の深さは人間が設計する
    AI に任せると「詳細 API でも ID のみ」「一覧 API でもフルネスト」など極端な設計になることがある。
    一覧=軽量 / 詳細=リッチ というルールを与えてから生成させるのが安全。


まとめ

レスポンス設計のベストプラクティス:

  • id は必須
  • 一覧は軽量、詳細はリッチ
  • 表示用フィールドを追加して UX を改善
  • ネスト構造は一覧と詳細で分ける
  • ステータスはコードとラベルを両方返す
  • 命名・日時・数値のルールを統一する

加えて、AI 活用では 「最初はおまかせ → 修正依頼で調整」 という流れを取ると効率的。
ルールを先に決めて共有し、その基準で AI が生成したコードを整合させるのが実務的な使い方になる。


次回は 認証・権限まわりの設計(DRF + Vue 編) を取り上げる予定。

Discussion