🍔

リソース設計 ~webサービス~

2024/08/03に公開

リソース設計とは?

リソース設計とは、webサービスで使用するデータをどの範囲で分割して、どのようにクライアントに提供するのかを設計する作業です。ここでの設計とは、システムをどのような構成でどのように開発するのかを検討し、図や文章に残す作業のことです。この設計がうまくできないと開発段階で無駄な工数が発生したり、開発途中で出戻りが起こったり、はたまた運用してからスケールを考える際にリプレイスを要求されたりなど、様々な問題に直面することになります。
もちろん、完璧な設計はありません。ですが、リソース設計をする上で良いとされているアプローチはあるので今回はそちらを紹介して、少しでもより良いリソース設計を目指しましょう!

リソース指向アーキテクチャのアプローチ

これは、次のステップでリソース設計をしていこうという設計方法になります。

①webサービスで提供するデータを特定する

②特定したデータをリソースに分割する

③各リソースにURIをつける

④クライアントに提供するリソースの表現を設計する

⑤リンクを利用してリソース同士を結びつける

⑥イベントの標準コースを検討する

⑦エラーについて検討する

以下でよくあるブログサイトを例にして、実際にリソース設計を行なっていきます。

ブログサイトのリソース設計

①webサービスで提供するデータを特定する

リソース設計の最初の工程は、サービスで提供するデータを理解して、特定することです。
今回のブログサービスでは、下記のデータを提供することが予想できそうです。

・Userデータ
・記事データ

②データをリソースに分ける

リソース設計では、この工程が最も難しい作業と言われています。
そもそも、リソースとはweb上に存在する名前のついた情報のことです。今回のサービスにおいて、提供する情報とはなんでしょうか?
まず、一番に考えられるのは記事情報です。ここがこのサービスで1番に提供したい情報であることは間違いないと思います。また、本サービスにはキーワードによる検索機能も存在します。この検索でヒットした記事もリソースと捉えることができます。ここで注意が必要なのが、検索機能自体はリソースではないという点です。あくまで、検索した結果(絞り込まれた記事)がリソースになります。
次は、User情報です。これもリソースになりえます。もちろん、記事情報に紐づいた情報になりますが、誰が書いた記事なのかは提供される一つの情報です。

③各リソースにURIをつける

次は、各リソースに対してURIで名前を付けていきます。
各リソースには、CRUDに基づいて四つの機能を考えます。

・ユーザー

取得(一覧、詳細)、作成、更新、削除:
GET /users
GET /users/{userId}
POST /users
PUT /users/{userId}
DELETE /users/{userId}

・ブログ記事

ユーザーに紐づく記事の取得(一覧、詳細)、作成、更新、削除:
GET /users/{userId}/posts
GET /users/{userId}/posts/{postId}
POST /users/{userId}/posts
PUT /users/{userId}/posts/{postId}
DELETE /users/{userId}/posts/{postId}

記事の検索結果:
GET /posts/search?query={query}

④クライアントに提供するリソースの表現を決定する

この工程は、作るサービスというよりかは、サービスをどのように作るかによって工夫がされる分野になります。
今回は、筆者がwebエンジニアで、よく使う構成としてバックエンドがRailsでフロントエンドがReactなので、フロントで融通が効くようにクライアントに提供するリソースの表現方法として、JSONを採用します。
JSONは、軽量でかつJSベースのReactとはもちろん、他のフレームワーク(Railsなど)にも様々なライブラリが提供されているので汎用的に使えるフォーマットと言えるでしょう。

⑤リンクを利用してリソース同士を結びつける

この工程では、これまで作成してきたリソース同士をリンクで結びつけます。
webの基本的な価値にリンクを辿ることで様々な情報にアクセスできるという点があります。
そのため、この工程は非常に重要で、そのwebサービスの価値に直結します。
ユーザがどのようにそのサービスを使うのかを考えた上で、どこからどこへ移動できたら便利なのかなどを想定して、リンクを付けていきます。
これから紹介するのはあくまで一例ですので、サービスの特徴や目指しているKPIによって工夫してみて下さい!

まず、考えられるのは記事に紐づいているユーザの一覧ではないでしょうか?
これは、サービスを使っているユーザの心理からすると、「こんなに面白い記事を書いている人の他の記事も見てみたい!」などが考えられます。

次は、逆にユーザ情報に紐づくそのユーザの書いた記事一覧などを考えます。
これは、もともと認知していたユーザの最新の記事を知りたい時などに使用されるリンクになるのでしょうか。

この工程は、サービスに左右される側面が大きいのでその都度試行錯誤をしながら考えていきましょう。

⑥イベントの標準コースを検討する

ここもサービスや目指すKPIによって大きく左右されるところだと思いますが、一旦二つのコースを考えてみます。

  1. キーワード検索から記事情報を見に行くパターン
    トップページを開く

ユーザーはブログサイトのトップページを開く。
GET / を実行して、トップページのHTMLを取得する。
検索キーワードを入力

ユーザーは検索バーにキーワードを入力し、検索を実行する。
検索クエリをサーバーに送信。
GET /posts/search?query={query} を実行して、検索結果のJSONを取得する。
検索結果を表示

検索結果のリストが表示される。
各検索結果には記事のタイトル、抜粋、著者情報などが含まれる。
特定の記事を選択

ユーザーは特定の記事をクリックして、記事の詳細ページを開く。
GET /users/{userId}/posts/{postId} を実行して、記事の詳細情報のJSONを取得する。

  1. 認知しているユーザーの記事を見に行くパターン
    トップページを開く

ユーザーはブログサイトのトップページを開く。
GET / を実行して、トップページのHTMLを取得する。
ユーザーを検索

ユーザーは検索バーに認知しているユーザーの名前を入力し、検索を実行する。
検索クエリをサーバーに送信。
GET /users?query={username} を実行して、ユーザーの検索結果のJSONを取得する。
ユーザーのプロフィールを表示

検索結果のリストから特定のユーザーを選択する。
GET /users/{userId} を実行して、ユーザーの詳細情報のJSONを取得する。
ユーザーのプロフィール情報が表示される。
ユーザーの記事一覧を表示

ユーザーのプロフィールページに表示される記事一覧から特定の記事を選択する。
GET /users/{userId}/posts を実行して、ユーザーの全記事のリストのJSONを取得する。
特定の記事を選択

ユーザーは特定の記事をクリックして、記事の詳細ページを開く。
GET /users/{userId}/posts/{postId} を実行して、記事の詳細情報のJSONを取得する。

⑦エラーについて検討する

一般的なエラーハンドリングの方法を考えます:

入力バリデーションエラー

クライアントが不正なデータを送信した場合、400 Bad Request を返す。
レスポンスボディに詳細なエラーメッセージを含める。
認証エラー

ユーザーが認証に失敗した場合、401 Unauthorized を返す。
権限エラー

ユーザーが許可されていない操作を試みた場合、403 Forbidden を返す。
リソースが存在しないエラー

ユーザーが存在しないリソースにアクセスしようとした場合、404 Not Found を返す。
サーバーエラー

サーバー内部でエラーが発生した場合、500 Internal Server Error を返す。

Discussion