RailsのREST設計のヒント集

# 参考URL
- まずはRailsガイド
https://railsguides.jp/routing.html

- TechRachoの記事
RESTの基本概念からRailsのルーティング作法まで書いてあります。一通り読んで見るのをおすすめします
[Railsのルーティングを極める(前編)](https://techracho.bpsinc.jp/baba/2020_11_18/15665)
[Railsのルーティングを極める (後編)](https://techracho.bpsinc.jp/baba/2020_11_20/15619)

- DHH流ルーティング
サブアクションとフィルタリングパターンについて
[DHH流のルーティングで得られるメリットと、取り入れる上でのポイント](https://tech.kitchhike.com/entry/2017/03/07/190739)
[DHHはどのようにRailsのコントローラを書くのか](https://postd.cc/how-dhh-organizes-his-rails-controllers/)

# 最初に
- Railsのroutingは多様ですが、こだわりすぎてもコスパが悪いと思っています
- RESTの原則とRailsの基本機能に従いつつ、ぴったり当てはまらない場合は愚直に定義するのが良いと思います

# RESTについて
- RESTは有名な概念にも関わらず、これだと思える解説がなかなかありません
- これは、そもそもの定義が非常にシンプルで、どう使うかはフレームワークや個人・チームの思想に委ねられているためです

Wikipedia

https://ja.wikipedia.org/wiki/Representational_State_Transfer　

個人的に重要だと思うのは以下の2つです
- URLはリソースを表す
- HTTPメソッドは操作を表す

## RESTではないURLとは
URLが動詞になっていたら、REST違反を疑うべきです

```
/add_user
/remove_user
/chat_room/1/join
```

# URLのサンプル集

## 基本のCRUD
`POST /articles`
articleを作成します

`GET /articles/1`
article1を参照します

`PUT /articles/1`
article1を更新します

`DELETE /articles/1`
article1を削除します

## `resources/id/field`でfieldを表す

`GET /users/1/password`
userのpasswordを参照します

`PUT /users/1/password`
userのpasswordを更新します

## フラグfieldのON/OFFをPUT/DELETEで表す
`PUT /articles/1/star`
お気に入り(star)を付与します

`DELETE /articles/1/star`
お気に入り(star)を削除します

DHH流ルーティングのサブアクションパターンです

## `resources/modifier` でフィルタリングを表す
`GET /messages/draft`
下書き状態のmessageを参照します
DHH流ルーティングのフィルタリングパターンです

# RESTを断念or難しいケース
- 個人的にRESTを断念するor判断が難しいケースのサンプルを書いていきます

## index,show以外の静的ページ
```
/resources_name/page1
/resources_name/page2
/resources_name/page3 ...
```
動的要素がほとんどない静的ページが必要になるケースもあると思います
コントローラーを分散させても分かりづらいだけなので、割り切って定義しています

```rb
resources :resources_name do
  collection do
    get :page1
    get :page2
    get :page3
  end
end
```

## 入退出を表す
チャットルームに入退出するAPIを考えます

**諦めてPOSTで表す**
```
POST /chatroom/1/join
POST /chatroom/1/leave
```
- URLが動詞になってしまっているのでRESTではありません
- HTTP methodに議論があるかもしれませんが、URLがRESTではなくなっている時点で大きな問題ではないと考えます
- SlackのAPIも似たような形式になっています
  - ※ Slackは明示的にRESTではないと[言っています](https://api.slack.com/web#slack-web-api__basics)
  - [参加API](https://api.slack.com/methods/conversations.join), [退出API](https://api.slack.com/methods/conversations.leave)

**フラグで表す**
```
PUT /chatroom/1/participation
DELETE /chatroom/1/participation
```
- 入室状況をフラグと捉えてPUTとDELETEで表しています

**サブリソースで表す**
```
POST /chatroom/1/members
DELETE /chatroom/1/members
```
- 参加メンバーを追加・削除するイメージで表しています

# PUTかPATCHか
個人的な見解
プロジェクト内で思想が統一されていればどちらでもいいと思います :innocent: 
Railsでどちらだけを使うならPATCHかなという印象です

---

参考資料

- [MSDN](https://developer.mozilla.org/ja/docs/Web/HTTP/Methods) HTTPの仕様
- [rubyonrails.org PATCH is the new primary HTTP method for updates](https://rubyonrails.org/2012/2/26/edge-rails-patch-is-the-new-primary-http-method-for-updates)
RailsのPATCH・PUTの扱いについて公式見解です
- [PatchとPutの違いについて](https://qiita.com/murata0705/items/52538c08778c39a91ec2)
`Railsでは、ユーザーが情報をまるごと置換えたと思ってもcreated_atとupdated_atがあるし、Putのような処理になることは少ないから、"PATCH is the new primary HTTP method for updates"にしたよとのこと。`
- [PUT vs. PATCH ~Kotlinでの部分更新はどちらを選ぶべきか？](https://blog.recruit.co.jp/rls/2019-12-06-put-vs-patch/)
---

- RailsのデフォルトはPATCH
- 主な違いは部分更新か、冪等性があるか
- ただしPATCHでも冪等性がある場合もある

---

部分更新とは

URLで表現するリソースをパラメーターで完全に表現する必要があるかどうか

- `PATCH /users/:id/profile, {name: "aaa", email: "bbb@examaple.com"}`
  - 部分更新
  - 他にも項目があるが、更新がなければ省略できる
- `PUT /users/:id/password, {password: "aaa"}` ※ passwordは必須
  - 部分更新ではない