APIのURIを短くする

June 8, 2017
API URI URL rails

Web API: The Good Partsを読んだのでその整理

URIを短くする

APIのURI設計をしていると、親子関係があるデータを扱う時URIが長くなる
例えば

  • blogが複数の記事をもつ
  • 記事は複数のコメントを持つ
  • コメントは複数の返信コメントをもつ

集合で表すと blogs ∋ articles ∋ comments ∋ replies
railsだと以下のようになる

$ rails routes
      Prefix Verb   URI Pattern                                                Controller#Action
     replies GET    /blogs/:id/articles/:id/comments/:id/replies(.:format)     replies#index
             POST   /blogs/:id/articles/:id/comments/:id/replies(.:format)     replies#create
       reply GET    /blogs/:id/articles/:id/comments/:id/replies/:id(.:format) replies#show
             PATCH  /blogs/:id/articles/:id/comments/:id/replies/:id(.:format) replies#update
             PUT    /blogs/:id/articles/:id/comments/:id/replies/:id(.:format) replies#update
             DELETE /blogs/:id/articles/:id/comments/:id/replies/:id(.:format) replies#destroy

とてもじゃないが、使えたものじゃない…
Herokuではどうしているかというと、

Limit nesting depth by preferring to locate resources at the root path. Use nesting to indicate scoped collections. For example, for the case above where a dyno belongs to an app belongs to an org:

/orgs/{org_id}
/orgs/{org_id}/apps
/apps/{app_id}
/apps/{app_id}/dynos
/dynos/{dyno_id}

Minimize path nesting by Heroku(HTTP API Design Guide)

つまり、ネストの深さを制限するのと親子は集合を表すのが大事

実際にやってみる

blogが複数の記事を持つものとする
集合で表すと blogs ∋ articles
articleをrailsでscaffoldすると次のリソースになる

$ rails routes
      Prefix Verb   URI Pattern             Controller#Action
    articles GET    /articles(.:format)     articles#index
             POST   /articles(.:format)     articles#create
     article GET    /articles/:id(.:format) articles#show
             PATCH  /articles/:id(.:format) articles#update
             PUT    /articles/:id(.:format) articles#update
             DELETE /articles/:id(.:format) articles#destroy

これが親子関係になると次のリソースになる

$ rails routes
      Prefix Verb   URI Pattern                       Controller#Action
    articles GET    /blogs/:id/articles(.:format)     articles#index
             POST   /blogs/:id/articles(.:format)     articles#create
     article GET    /blogs/:id/articles/:id(.:format) articles#show
             PATCH  /blogs/:id/articles/:id(.:format) articles#update
             PUT    /blogs/:id/articles/:id(.:format) articles#update
             DELETE /blogs/:id/articles/:id(.:format) articles#destroy

が、ネストが深い
ここでHerokuのURI設計を参考にするとこうなる

$ rails routes
      Prefix Verb   URI Pattern                       Controller#Action
    articles GET    /blogs/:id/articles(.:format)     articles#index
             POST   /blogs/:id/articles(.:format)     articles#create
     article GET    /articles/:id(.:format)           articles#show
             PATCH  /articles/:id(.:format)           articles#update
             PUT    /articles/:id(.:format)           articles#update
             DELETE /articles/:id(.:format)           articles#destroy

新規作成と一覧取得は親子関係の状態で持ってくる, 作成するのでそのまま。
詳細取得と更新、削除は一意な値で判断して編集するので、省略できる。
blogに属さない記事は存在しないので、こんな感じで良さそう。