Webサイトを作る時のURLはどう定義すれば良いのか

# はじめに

どうも、 @rabeneko と申します。
私は、N予備校( https://www.nnn.ed.nico/ )という学習サイトでプログラミング講師をしております。
N予備校では毎週火曜日と金曜日にプログラミング授業をしておりまして、そこで出た質問の解説をしております。
今回は、その授業中に出た、 **「Webサイトを作る時のURLは、どう定義すれば良いのか」** という質問に対する回答をQiitaに書きたいと思います。

プログラミングを学んでいる方・学んでみたい方は、ぜひN予備校の授業を覗いてみてください。

https://www.nnn.ed.nico/pages/programming/

# Webサイトを作る時のURLは、どう定義すれば良いのか

一通りプログラミングを学んだ後、「はい、では自由に作ってくださいね！」なった時によくつまづくのが、「自由すぎてどう作ったら良いのか分からない」というものです。
他の分野の勉強と違って、 **プログラミングには「ただ一つの正解」というものはありません。**
今回の「Webサイトを作る時のURL」もその一つです。

# まずはいきあたりばったりでやってみる

今回は簡単なメモ帳アプリで考えてみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1972052/b2a0f58e-f481-9e57-9e04-e94607ece9cb.png)

メモ帳アプリに必要な機能の一覧、これもまた正解は無いので、考える必要があります。

まずは、いきあたりばったりで作ってみることにします。（自由ですからね！）

今回は本当にテキストだけのただのメモの追加と、その一覧の表示があると考えたとしましょう。
これであれば、以下の3つのページで実現できそうです。

|  ページ名  |  やること  |
| ---- | ---- |
|  メモ一覧ページ  |  データベースからメモの一覧を取ってきて表示する  |
|  メモの追加ページ  |  メモの追加フォームを表示する  |
|  フォームで入力されたメモの受付先  |  メモの追加フォームで入力された文字をメモとしてデータベースに保存する。その際の受付URL  |

これらの3つのURL、別になんでもいいんです。

|  ページ名  |  URL  |
| ---- | ---- |
|  メモ一覧ページ  |  https://memoservice.jp/  |
|  メモの追加ページ  |  https://memoservice.jp/form  |
|  フォームで入力されたメモの受付先  |  https://memoservice.jp/uketsuke  |

※ https://memoservice.jp は適当です…！


このURLの定義でも、サービスはできます。（自由ですね）

フォームはこんな感じ

![スクリーンショット 2022-01-12 16.08.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1972052/fcfe4b33-b6da-d17f-5c2b-157ea1f11c41.png)


メモ一覧は、データベースのmemosテーブルに、以下のように保存されるとします。

|  text  |
| ---- |
| テスト |
| こんにちは |
| テスト |

この1行1行がメモだとします。

## 編集機能の追加

次に、メモの編集機能を足したいとなったとします。

いろんなサービスに、編集機能はありますね。

もちろん、Twitterのように編集できないサービスもありますので、「編集機能が無いと不正解」ではないです。（そのへんは柔軟に…！）

「編集フォーム」と、「フォームで入力されたメモの受付先」の2つのURLを考える必要がありそうです。

が、追加の時に、formやuketsukeを作ってしまいましたので、別のものを考える必要がありそうですね。

|  ページ名  |  URL  |
| ---- | ---- |
|  メモ一覧ページ  |  https://memoservice.jp/  |
|  メモの追加ページ  |  https://memoservice.jp/form  |
|  追加ページのフォームで入力されたメモの受付先  |  https://memoservice.jp/uketsuke  |
|  メモの編集ページ  |  https://memoservice.jp/henshu_form  |
|  編集ページのフォームで入力されたメモの受付先  |  https://memoservice.jp/henshu_uketsuke  |

でもこれだと、編集ページで「どのメモを編集するか」がわかりませんね。

データベースのmemosテーブルでは以下のように保存されています。

|  text  |
| ---- |
| テスト |
| こんにちは |
| テスト |

そこで、テストを編集したい時は、

|  ページ名  |  URL  |
| ---- | ---- |
|  メモの編集ページ  |  https://memoservice.jp/henshu_form?text=テスト  |
|  編集ページのフォームで入力されたメモの受付先  |  https://memoservice.jp/henshu_uketsuke?text=テスト  |

という風に、どのメモを編集したいかを送ってもらうようにしましょう。



次に、メモの1番目の「テスト」を「おはようございます」に、3番目の「テスト」を「こんばんは」と変更したいとします。

データベースのデータを編集するにはSQLを使いますが、 

```
UPDATE memos SET text = "おはようございます" WHERE text = "テスト"
```

のようなSQLを発行して実行します。

このSQLを実行すると、以下のようになります。

|  text  |
| ---- |
| おはようございます |
| こんにちは |
| おはようございます |

3番目のテストも「おはようございます」になってしまいます。
SQLには「何番目の」のような指定はかなーり難しいです。（できなくはないけど）
そして、3番目のテストが書き換わってしまいましたので、

```
UPDATE memos SET text = "こんばんは" WHERE text = "テスト"
```

は、データが見つからずエラーになってしまいます。

これでは、編集するたびに全く関係ないところが変更されてしまいますので、メモに「タイトル」を付けて、メモにタイトルの入力欄を付けて、タイトルを指定して編集するという風にしてみましょう。

![スクリーンショット 2022-01-12 16.08.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1972052/415f2f0a-c80d-71fb-e82b-caa828e0da1e.png)


つまりデータベースのmemoテーブルは

|  title  |  text  |
| ---- | ---- |
| メモ1 | テスト |
| メモ2 | こんにちは |
| メモ3 | テスト |

になるということです。

URLはこんな感じ…！

|  ページ名  |  URL  |
| ---- | ---- |
|  メモの編集ページ  |  https://memoservice.jp/henshu_form?title=メモ1  |
|  編集ページのフォームで入力されたメモの受付先  |  https://memoservice.jp/henshu_uketsuke?title=メモ1  |

これで1つ編集したら複数編集されることは無くなったように見えます。

でも利用者の方が、タイトルを絶対かぶらないように作ってくれる保証は無いですよね（汗）

|  title  |  text  |
| ---- | ---- |
| 今日の予定 | 勉強する |
| 今日の予定 | 買い物に行く |
| 今日の予定 | 郵便物を出す |

みたいなメモになったら、3行とも書き換わってしまいますね（涙）

なので、タイトルではない、絶対に他の行とかぶらないデータを作るのが良さそうです。

※ ただしwikipediaのように、タイトルがかぶらないというルールにしてサービスを作っているところもあります。タイトルで管理するのが絶対ダメということは無いです。



そして次はメモの削除機能が欲しいとなったら、またURLを考えないといけないですね。

# 先人たちの知恵を借りる

そもそもとして、自由な世界で自由にやって、いけてないアプリを作るのは素晴らしい経験です。
かのイチロー先生も「無駄なことはできるだけやった方が良い」と言っていました。

https://news.tbs.co.jp/newseye/tbs_newseye4445295.html

無駄な経験が、理解をより深めてくれます。

という前置きはさておき、「URLの定義」や「どんな機能が必要か」というのは何人もの先人たちが考えに考えて、「基本的にはこういうもの」というものを用意してくれています。
それが **CRUD** と **RESTfulな考え方** です。

## CRUDとは

CRUDは「作成（Create）」「読み出し（Read）」「更新（Update）」「削除（Delete）」の頭文字を取ったもので、何らかのデータを扱う時に必要な基本機能です。
今回のような「メモ」を扱う時は、 **「メモの作成」「メモの表示」「メモの更新」「メモの削除」という4つの機能が考えられますよということです。**

4つとも絶対作らないといけないわけではないのもポイントです。

## RESTfulな考え方とは

「利用者がどのような機能を欲しているか」という視点でWebサービスを作るのではなく、「データを主人公にして、データと、CRUDの4機能にあったHTTPメソッドをベースにURLを作っていく」というのがRESTfulな考え方です。

本当はRESTfulには様々な定義があるんですが、分かりやすくするために一部の考え方を借ります。

RESTfulの考え方をそのまま当てはめると、以下のようなURLができることになります。

|  ページ名  |  メソッド  |  url  |
| ---- | ---- | ---- |
| メモ一覧ページ | GET | https://memoservice.jp/memos |
| メモ個別ページ | GET | https://memoservice.jp/memos/{id} |
| 追加するメモの受付先 | POST | https://memoservice.jp/memos |
| 編集するメモの受付先 | PUT | https://memoservice.jp/memos/{id} |
| 削除するメモの受付先 | DELETE | https://memoservice.jp/memos/{id} |

このように、 **「考えなくても、RESTfulな考え方に乗ればそれらしいURLができるじゃーん」** というメリットはあります。
それとは別に、**「あれっフォームのURLが無いじゃん」「HTMLのフォームはGETメソッドとPOSTメソッドしか送れないよー」** という2つの問題も出てきます。

RESTfulな考え方では、「データが主人公」ですので、 **どこからリクエストが来るかという所を気にしない** というポイントがあります。

どういう事かと言いますと、今はWebブラウザのことしか考えていませんが、大手のWebサービス（例えばニコニコやYoutube等）は「iOSアプリ」「Androidアプリ」「PS4やPS5」「ニンテンドースイッチ」等のプラットフォームでもサービスを展開していますよね。

これらのサービスはHTMLではなく、それぞれバラバラな言語で開発されています。
iOSアプリ向け、Androidアプリ向けとそれぞれ分けてプログラムを書くのは大変ですので、どこから来ても良いように統一した物となっています。
そのため、本当はHTMLが返ってくるということも無いんです。(どのプラットフォームでも大丈夫なようにJSON等で返る)

なので、「あれっフォームのURLが無いじゃん」「HTMLのフォームはGETメソッドとPOSTメソッドしか送れないよー」という問題には、 **「RESTfulな考え方とは別にURL考えてね」** となります。

そして `{id}` ですよね。
これは、メモ1つ1つを識別するものを入れます。（これを英語でidと言います）
いろんな正解があるのですが、一番基本的な考え方は「自動で番号が発番されるidというカラムを作って、それをidとする」のが一般的です。
なので、特別な事情がない限りは、**「自動で番号が発番されるidというカラム」** を作ってください。

| id |  title  |  text  |
| ---- | ---- | ---- |
| 1 | 今日の予定 | 勉強する |
| 2 | 今日の予定 | 買い物に行く |
| 3 | 今日の予定 | 郵便物を出す |

こんな感じで、予定を作るごとにidが自動で振られるようにします。

なので、id1番の予定について色々扱う場合は

|  ページ名  |  メソッド  |  url  |
| ---- | ---- | ---- |
| メモ個別ページ | GET | https://memoservice.jp/memos/1 |
| 編集するメモの受付先 | PUT | https://memoservice.jp/memos/1 |
| 削除するメモの受付先 | DELETE | https://memoservice.jp/memos/1 |

となります。

あとはPUTとDELETEですよね。
RESTfulな考え方に完全に従うのであれば、HTMLのフォームを使わずにjavascriptで送るのが正解なのですが、HTMLのフォームを使いたいのであれば、POSTで送ることになります。

|  ページ名  |  メソッド  |  url  |
| ---- | ---- | ---- |
| メモ個別ページ | GET | https://memoservice.jp/memos/1 |
| 編集するメモの受付先 | POST | https://memoservice.jp/memos/1 |
| 削除するメモの受付先 | POST | https://memoservice.jp/memos/1 |

「編集するメモの受付先」と「削除するメモの受付先」は同じですが、パラメータで分けるようにします。
POSTメソッドなのでパラメータはURLにのりませんが、あえてURLに載せるなら以下のようになります。

|  ページ名  |  メソッド  |  url  |
| ---- | ---- | ---- |
| メモ個別ページ | GET | https://memoservice.jp/memos/1 |
| 編集するメモの受付先 | POST | https://memoservice.jp/memos/1?mode=edit |
| 削除するメモの受付先 | POST | https://memoservice.jp/memos/1?mode=delete |

パラメータは、「何をするかが分かればいい」ので、edit=1とか、delete=1とかでも大丈夫です。（このあたりはRESTfulな考え方から離れているので、分かれば良い）

|  ページ名  |  メソッド  |  url  |
| ---- | ---- | ---- |
| メモ一覧ページ | GET | https://memoservice.jp/memos |
| メモ個別ページ | GET | https://memoservice.jp/memos/{id} |
| メモの追加ページ | GET | https://memoservice.jp/memos/new |
| 追加するメモの受付先 | POST | https://memoservice.jp/memos |
| メモの編集ページ | GET | https://memoservice.jp/memos/{id}/edit |
| 編集するメモの受付先 | POST | https://memoservice.jp/memos/{id}?mode=edit |
| メモの削除ページ | GET | https://memoservice.jp/memos/{id}/delete |
| 削除するメモの受付先 | POST | https://memoservice.jp/memos/{id}?mode=delete |

削除ページは作らないことも多いですね。「削除してよろしいですか？」みたいなダイアログを出してOKが押されたら削除するメモの受付先にPOSTすることが多いです。

先人の知恵をフルに活かすことで、基本的なURLは何も考えずにできます。

ここから、一括追加したいとか、メモ一覧ページはトップページにしたいとか、そういうカスタマイズ的な所はゆっくり考えていくという話になります。

# いろんなサービスの通信を見るのもオススメ

URLの定義はサービスの数だけ答えがあります。
普段使っているGoogleやAmazon、Twitterなどの通信を見て、どんなURLが定義されているか、どんなメソッドが使われているかを確認するのもオススメです。

正解が無くて難しい分野ですが、ぜひいろいろ考えて、自分が良いと思うURLの定義をしてみてくださいね…！