「わかりやすいURL」と「正しいURL」は別物だ。
エンジニアになりたての頃、URLの設計を深く考えたことがなかった。/getUser?id=1 でも /user/1 でも「動けばいい」と思っていた。『Webを支える技術』を読んで、URIには設計思想があり、それを守ることにちゃんと意味があると初めて理解した。
URIとURLの違いから始める
まず用語の整理から。
URL(Uniform Resource Locator)はリソースの「場所」を示す。URI(Uniform Resource Identifier)はリソースの「識別子」を示す概念で、URLを包含する上位概念だ。
実務ではほぼ同じ意味で使われるが、『Webを支える技術』が強調するのは「URIはリソースを識別するもの」という考え方だ。場所ではなく識別子として設計する、という視点の違いが、良いURI設計につながる。
良いURIの原則
著者の山本陽平氏が挙げる良いURIの条件を整理する。
動詞を含めない
悪い例:
/getUser
/createPost
/deleteComment?id=5
良い例:
/users
/posts
/comments/5
URIはリソース(名詞)を表すものであり、操作(動詞)はHTTPメソッド(GET・POST・PUT・DELETE)が担う。動詞をURIに含めると、HTTPメソッドと役割が重複して設計が崩れる。
階層構造でリソースの関係を表す
/users/123 # ユーザー123
/users/123/posts # ユーザー123の投稿一覧
/users/123/posts/5 # ユーザー123の投稿5
スラッシュで区切った階層がリソースの親子関係を表す。これを守ることで、URLを見ただけでデータ構造が推測できる。
拡張子は含めない
# 悪い例
/users/123.json
/posts/5.html
# 良い例
/users/123
/posts/5
フォーマット(JSON・HTML・XMLなど)はHTTPヘッダーの Accept で指定するのが本来のやり方だ。URLにフォーマットを含めると、同じリソースに複数のURLが生まれて管理が煩雑になる。
変わらないURLを目指す
Tim Berners-Lee(WWWの発明者)の言葉「Cool URIs don’t change(クールなURIは変わらない)」が本書でも引用されている。
一度公開したURIが変わると、外部からのリンクが切れ、検索エンジンの評価もリセットされる。設計時に「将来も変わらないか」を問うことが重要だ。
# 変わりやすい(実装の都合が透けている)
/php/user.php?id=123
/v1/2024/users/123
# 変わりにくい(リソースの本質だけ)
/users/123
実務で詰まったURI設計
「動作」をURIに入れたくなる誘惑
以前、ユーザーのパスワードリセット機能を作ったとき、こんなURIを設計してしまった。
POST /resetPassword
正しくは「パスワードリセットリクエスト」というリソースを作る発想が必要だ。
POST /password-reset-requests
名詞で表現できないと感じるときは、リソースの抽象化が足りていないサインだ。
検索・フィルタリングはクエリパラメータで
GET /posts?tag=TypeScript&page=2&per_page=20
リソースの絞り込みや並び替えはクエリパラメータで表現する。パスに含めると組み合わせの数だけURLが必要になって破綻する。
バージョニングはどこに入れるか
APIのバージョンをURIに含める方法は議論があるが、実務では最もわかりやすいパス方式が多い。
/api/v1/users # パスに含める(よく見る)
/api/users # Acceptヘッダーで指定(理想的だが実装が複雑)
どちらにするかより、一度決めたら一貫して守ることの方が重要だ。
EDCシステムのAPI設計で「URI変更の痛み」を体験した
治験管理システムを製薬会社の外部システム(EDC)と連携させたとき、APIのURI設計で後悔する経験をした。
最初に設計したAPIは POST /updateSubjectStatus のようなRPC的なURIだった。「動けばいい」という発想で設計してしまった。接続先の製薬会社にAPI仕様書を渡し、テスト環境での連携が完成した後で、「やっぱりRESTfulなURIにしたい」と変更しようとしたとき、すでに遅かった。
外部に公開したAPIのURIを変えるには、製薬会社側のシステムも変更してもらう必要がある。治験システムの連携仕様変更は変更管理プロセスを経る必要があり、数週間の調整コストが発生した。
この経験から「外部連携するAPIのURIは最初から丁寧に設計する」が鉄則になった。
治験システムのリソース設計では、以下のように整理した。
GET /subjects 被験者一覧
POST /subjects 被験者登録
GET /subjects/:id 被験者詳細
GET /subjects/:id/visits 来院一覧
POST /subjects/:id/visits 来院記録作成
GET /subjects/:id/visits/:visitId/assessments 検査結果一覧
この構造にしたことで、「どのリソースを操作しているか」がURLを見るだけで明確になった。製薬会社の技術担当者にも「直感的でわかりやすい」と言ってもらえたし、ドキュメントを書く量も減った。
URIの設計はAPIの品質に直結する
URIを雑に設計すると、後からの変更が難しくなる。一度外部公開したAPIのURIを変えると、利用者全員に影響が出る。
『Webを支える技術』を読んで最も印象に残ったのは、「WebはURIという仕組みでリソースを識別することで、これだけ巨大なシステムになった」という視点だ。自分が設計するURIも、その延長線上にある。
URLを「動けばいい文字列」ではなく「リソースの識別子」として設計する習慣が、APIの品質と保守性を長期的に高める。