初心者でも理解できるRESTful APIのURL設計完全ガイド

目次

はじめに

この章では、本記事の目的と読み方、想定する読者について簡潔に説明します。RESTful APIのURL設計を学ぶ際の心構えと、以降の章で扱う内容の全体像を示します。

目的

本記事の目的は、保守性と拡張性の高いRESTful APIのURL設計を実務的に学ぶことです。具体例を使ってわかりやすく説明しますので、設計の判断に迷ったときに参照できる指針を提供します。

対象読者

API設計に携わるエンジニア、バックエンド開発者、フロントエンドとバックエンドの連携を担当する方を想定します。初心者にも配慮して、専門用語はできるだけ噛み砕いて説明します。

本記事の構成と読み方

全8章で構成します。第2章から第7章で具体的な原則やパターン、実例とアンチパターンを順に解説します。まずは第2章の基本原則を読むと、以降の内容が理解しやすくなります。例を多く示すので、自分のプロジェクトに当てはめて考えてください。

前提

認証や認可、HTTPメソッド(GET/POST/PUT/DELETE)の基本的な意味は知っている前提で進めます。知らない方は最小限の用語説明を加えますので安心してください。

RESTful API URL設計の基本原則

はじめに

RESTful APIではURLがそのAPIの使いやすさを大きく左右します。ここでは基本的な考え方をやさしく説明します。

原則1: リソースは具体的な名詞で表現する

URLには操作を表す動詞を入れず、ユーザーや記事、商品などの名詞を使います。例: /users, /articles, /products

原則2: 操作はHTTPメソッドで表す

作成はPOST、取得はGET、更新はPUTまたはPATCH、削除はDELETEを使います。例: GET /users, POST /users

原則3: 一意性と階層構造

各リソースに一意なパスを割り当てます。ネストで関係性を表現します。例: GET /users/123、GET /users/123/orders

原則4: 複数形を使う

コレクションには複数形を使うと直感的になります。例: /users, /orders

原則5: IDや識別子の扱い

IDは可能な限り短く明瞭にします。複合キーや検索的表現はクエリパラメータへ回します。例: GET /products/456, GET /products?category=books

実用のヒント

アクション的なエンドポイント(/getUserや/deleteItem)は避け、汎用性を高めてください。バージョンは必要なら先頭に置きます(/v1/users)。

URL命名規則とパターン

基本方針

  • リソースは名詞で表し、複数形で統一します。例: /users, /orders
  • 小文字とハイフンを使い可読性を高めます。例: /user-profiles
  • ファイル拡張子や大文字は避けます。例: /users.json は使わない

構造とパターン例

  • 階層はスラッシュで区切ります。例: /users/{userId}/orders
  • 単純で意味のある名前を選び、長すぎないようにします。例: /products/123 rather than /catalogue/items/product-details/123
  • バージョンは先頭に入れることが一般的です。例: /v1/users

動詞の扱いと例外

  • 基本は名詞のみで設計し、操作はHTTPメソッド(GET/POST/PUT/DELETE)で表現します。
  • 認証や検索など、リソースでない操作は短い動詞で例外的に許容します。例: /login, /search

禁止・注意点

  • 動詞的なエンドポイント(/getUser)や実装依存名(/get_user.php)は避けます。
  • 複雑すぎるURL、意味が不明瞭な識別子は避けてください。

実践のヒント

  • 一貫性を最優先にします。チームでスタイルガイドを作り、例外を明確にしてください。

階層構造とネストの表現

基本概念

リソース間の親子関係はURLの階層で表現します。例: ユーザー123の投稿一覧は GET /users/123/posts、特定投稿は GET /users/123/posts/456 です。POST /users/123/posts で新規投稿を作れます。こうすることで関係性が直感的に伝わります。

ネストすべき場合と避ける場合

ネストは「親→子」が明確なときに使います。たとえば投稿とコメントの関係です。一方、子リソースがグローバルに一意なら /posts/456 のように親を省略しても構いません。深いネスト(3階層以上)は可読性が下がるため避けるのが無難です。

深さの目安と代替

一般的にネストは1〜2階層までに留めます。深くしたい場合はクエリパラメータ(?post_id=456)や関連エンドポイント(/posts/456/comments)を検討します。

実用例

  • コレクション取得: GET /users/123/posts
  • 単一取得: GET /posts/456(IDが一意な場合)
  • 作成: POST /users/123/posts
  • アクション: POST /posts/456/likes のように関係リソースで表現します。

注意点

URLに親のIDを含める場合はサーバー側で親子関係を検証してください。IDはURLエンコードし、可読性を優先してハイフンやUUIDを使い分けます。

クエリパラメータによるフィルタ・ソート

概要

リスト表示や検索ではクエリパラメータで条件を渡します。URLに条件を付けるとクライアントが自由にデータを取得できます。例: /posts?author=123&sort=created_at&order=desc

フィルタリングの基本

よく使う形式は key=value です。例: /users?status=active
複数条件は & でつなぎます。例: /posts?author=123&tag=5
部分一致や全文検索は q=term のような汎用パラメータを用いると扱いやすいです。

よく使う演算子と表現

  • 等価: status=published
  • in(複数指定): tags=1,2,3 または tags[]=1&tags[]=2
  • 範囲: created_after=2024-01-01&created_before=2024-02-01
  • 部分一致: q=keyword

ソート

ソートは sort と order を使うか、符号付きの sort を使います。例: /posts?sort=created_at&order=desc または /posts?sort=-created_at
複数キーはカンマ区切りで指定します: sort=created_at,-title

ページネーションと制限

limit/offset と page/per_page のどちらかを採用します。例: /users?status=active&limit=10&offset=20
レスポンスで総件数や次ページの情報を返すと親切です。

バリデーションと設計の注意点

  • 許可するフィールドをホワイトリスト化する
  • limit の上限を設ける(例: max 100)
  • 型チェックと日付フォーマットを明確にする
  • URLエンコードを忘れない
  • 内部フィールドを直接公開しない

組み合わせ例

/posts?author=123&tag=5&q=API&sort=-created_at&limit=10&offset=0
このように組み合わせると柔軟なデータ取得が可能です。

実践例とアンチパターン

概要

実践では、リソース指向で動詞を含まないURLを使い、HTTPメソッドで操作を表現します。ここでは良い例と悪い例、よくあるミスと改善方法を分かりやすく示します。

良い設計の具体例

  • ユーザー一覧を取得: GET /users
  • ユーザー作成: POST /users
  • ユーザー更新: PUT /users/123
  • ユーザー削除: DELETE /users/123
  • ネスト例(そのユーザーの注文): GET /users/123/orders, POST /users/123/orders
  • フィルタ例: GET /orders?status=shipped&sort=-created_at
    これらは名詞を使い、階層で関係を表しています。可読性が高く、クライアントとサーバーの役割が明確です。

悪い例(アンチパターン)

  • 動詞を含むエンドポイント: /getUsers、/createUser
  • アクションをパラメータ化する: /users?action=delete&id=123
  • HTTPメソッドの誤用: GET /deleteUser?id=123 や POST /users/123 を更新に使う
  • モノリシックな汎用エンドポイント: POST /api {“action”:”createUser”,…}
    こうした設計は直感性を失い、キャッシュや認可の扱いが難しくなります。

よくあるミスと改善方法

  1. 更新をPOSTで行う → PUTかPATCHに切り替える。PUTは全体更新、PATCHは部分更新です。
  2. リソースIDをクエリに置く → パスに含める(/users/123)。可読性とRESTの意図が明確になります。
  3. 過度なネスト → 3階層以上は避け、必要なら別リソースにする(/users/123/orders → /orders?user=123 も検討)。
  4. 単一エンドポイントで全て処理 → 機能ごとにリソースを分け、責務を分離します。

実例を真似し、アンチパターンを避けることで保守性と拡張性が向上します。

その他のベストプラクティス

命名規則の一貫性

リソース名は複数形・小文字・ハイフンで統一すると学習コストを下げられます。例: /users, /order-items。IDはパスに置き、クエリは検索や絞り込みに使います。例: /users/123, /orders?status=paid

HTTPメソッドの正しい割り当て

各操作に意味を持たせます。主な割当て例:
– GET: 取得(/users、/users/123)
– POST: 作成(/users)
– PUT/PATCH: 更新(PUTは全体更新、PATCHは部分更新)
– DELETE: 削除(/users/123)
具体例を示すと直感的になります。

APIバージョニング

後方互換性を保つためにバージョン管理を行います。URLにバージョンを含める方法が分かりやすいです。例: /v1/users。大規模な変更時に新しいバージョンを用意すると安全に改修できます。

目的に沿った簡潔なURL設計

URLに動詞を入れず、リソース中心で設計します。悪い例: /getUserById?id=123。良い例: /users/123。長すぎるパスや無意味な階層は避けます。

エラーハンドリングとステータスコード

意味のあるHTTPステータスを返します。成功は200/201/204、クライアントエラーは400/404/409、サーバーエラーは500系で表現します。201を返す場合はLocationヘッダで新規リソースを示すと親切です。

セキュリティと認証

常にHTTPSを使用し、トークンはAuthorizationヘッダに載せます(例: Bearer トークン)。パスやログに機密情報を含めないでください。レート制限や入力検証も実装し、悪用を防ぎます。

まとめ

以下は、これまでの章で扱った重要なポイントを分かりやすく整理したまとめです。

  • リソース指向で設計する:URLは操作ではなく『何を扱うか(名詞)』を示します。
  • 一貫した命名:複数形、スネークケースやケバブケースなどチームで統一します。
  • HTTPメソッドで責務を分離:GET/POST/PUT/PATCH/DELETEを意味どおりに使います。
  • 階層は必要最小限に:親子関係は表現しますが、過度なネストは避けます。
  • フィルタ・ソートはクエリに:検索条件や並び替えはクエリパラメータで扱います。
  • 変化に備える:バージョン管理とエラーハンドリングを設計段階で組み込みます。

実践チェックリスト

  1. エンドポイントを名詞で表現できているか確認する。
  2. 同じ意味のパスで別ルールがないか点検する。
  3. ネストが深すぎないか、代替案(リソースID参照)を検討する。
  4. 認証・バージョンの方針をドキュメント化する。

最後に、良いURL設計は読みやすさと将来の拡張を助けます。小さなルールを守るだけで、保守性と利用者の満足度が大きく改善します。

よかったらシェアしてね!
  • URLをコピーしました!

この記事を書いた人

目次