RailsのURL設計を考えてみる(6) 設計の選択肢

今回は直接Railsとは関係ないのですが、先日こういうページを見つけました。

これは2009年に書かれたもののようですが、URL設計に関する重要な考え方がいろいろ書かれています。
その中に、このブログのシリーズの(4) スラッシュと「持っている」関係(5) Railsのリソースパターンの前段階になるような“Choosing a URI schemes for resource hierarchies”という話があったので、かいつまんで紹介したいと思います。

リソースの階層に対して、どういうURLを設計するか?

前提として、設計するWebサイトには、conversation(会話)というリソースが複数あり、それぞれのリソースはユニークなIDで区別されるとします。(IDは数字とは限らない識別子)

/conversations/conversation/{id}
  • /conversations ですべての会話
  • /conversation/{id} でID=idの会話

全体の会話は複数形、特定の1つの会話は単数形という考え方。
英語としては自然なのかもしれませんが、わざわざ使い分けるほどの意義は薄いし、後者でパスを削った /conversation は何を指すのかという問題が残ります。

/conversations/conversation/{id}
  • /conversations ですべての会話
  • /conversations/conversation/{id} でID=idの会話

先ほどと比べると1種類のパスに統合されましたが、やはり /conversations/conversation が何を指すのかが謎です。

/conversations/{id}
  • /conversations ですべての会話
  • /conversations/{id} でID=idの会話

Rails方式です。これでパスを削っても問題なくなりました。ただし、新しい会話を作成するための画面に用いる /conversations/new という補助的リソースが、ID=newのリソースと区別できなくなるという問題があります。これは比較的小さな問題ではありますが、前の2つの方式ではこの問題は起こりません。

/conversations/conversation-{id}
  • /conversations ですべての会話
  • /conversations/conversation-{id} でID=idの会話

それを解決した方法。ただしちょっと冗長ではあります。

深い階層

次に、それぞれのconversationがtodo list(やることリスト)というリソースを複数持っているとします。

/conversations/{cid}/todo-lists/{tid}
  • /conversations/{cid}/todo-lists でID=cidの会話が持つすべてのやることリスト
  • /conversations/{cid}/todo-lists/{tid} でID=cidの会話が持つID=tidのやることリスト

Rails方式。前節と同じ問題は引き継ぎます。
また、 /conversations/{cid}/todo-lists (やることリストの全体)は実際には必要なく、 /conversations/{cid} があればそれで十分なことがあります((日付をURLに入れるとき、わざわざ /years/2012/months/01/days/03 とする必要がないのにも似ています))。

/conversations/{cid}/{tid}
  • /conversations/{cid}/{tid} でID=cidの会話が持つID=tidのやることリスト

tidが何を指しているのかがよくわかりません。日付など明らかにわかるような場合なら短くていい方式でしょう。

/conversations/conversation-{cid}/todo-list-{tid}
  • /conversations/conversation-{cid}/todo-lists-{tid} でID=cidの会話が持つID=tidのやることリスト

前節の最後の方法を採用しつつ、todo listの全体はいらないのだから、そのパス階層だけなくした方式。この方式だと、全体のリソースと個別のリソースのどれを提供しているかが明確になります。

私見

Rails方式でいいじゃん(笑)
と言ってしまうと元も子もないのですが、こういうような議論を経て、今のRailsのリソースパターン(Memberリソース、Collectionリソースなど)が定まってきたのではないか、と想像できます。

Rails方式における /conversations/new の問題点については、実は過去には /conversations;new となっていた時期がありました。これなら問題は起きないのですが、セミコロンが不自然であまり受け入れられなかったのか、すぐにスラッシュに変わりました。
個人的な考えでは、こういう補助的なリソースは“_”で始めることとして、 /conversations/_new とすればいいのではと思っています*1。ただしRailsの規約で“_”はpartial viewを指すので、ちょっと相性が悪いかもしれません。

もちろん、Railsを使うときもこれらの方式のどれを実際に採用するかは自由です。routes.rbの書き方次第で、どのような方式にすることもできます。ただ、Railsのパターンに従ってresourcesで書くのが楽ですよ。

*1:GitHubがこの方式を採用しています