Serverless Operations, inc

>_cd /blog/id_6zp8gbrwmsu

title

REST APIを設計する際に知っておきたい基礎知識

summary

本記事ではREST APIを開発するに際して守るべきAPI設計の基本原則について解説しています。REST APIの設計において、基本原則を守ることは非常に重要です。これにより、APIは理解しやすく、メンテナンスが容易で、拡張性の高いものになります。開発チームでは、共通の原則に基づくことで設計のばらつきがなくなり、効率的な開発が可能になります。また、API利用者にとっても、基本に忠実な設計は仕様を理解しやすく、使いやすいAPIを提供します。このように、双方にとってメリットの大きい設計が実現できます。

Web APIとREST APIとは

Web APIの概念図

WebAPIとは「HTTPプロトコルを利用してネットワーク越しに呼び出すAPI」です。APIとは”Application Programming Interface”の略で、ソフトウェアの機能はわかっているけれども中身の動作は詳しくわからない機能の塊を外部から呼び出すための仕組みです。プロトコルとしてHTTPを使うため、そのエンドポイントはURLによって指定されることになります。

REST APIの概念図

REST APIとはWeb APIを使ってデータをやり取りするための規約の一つです。URLですべてのリソース(データ)を表現し、GETやPOSTといったメソッドでリソースへの操作方法をしていします。クライアントからリクエストを送信するとその応答をJSONやプレーンテキスト、XMLなどで受け取ることが出来ます。

例:ユーザAPI( https://reqres.in/api/users )

RestにおけるエンドポイントとHTTPメソッドの設計

まずはオーソドックスなブログ投稿型のアプリケーションを考えてみましょう

必要な機能のリストアップ

まずはAPIとしてどういった機能を実装する必要があるのかをリストアップしましょう。これらをベースにしてエンドポイントと割り当てるHTTPメソッドを設計していきます設計していきます。

  • ユーザの登録
  • ユーザの更新
  • 記事の投稿
  • 記事の一覧の取得
  • 記事の詳細の取得
  • 記事に紐づくコメントの一覧取得
  • コメントの詳細の取得
  • コメントの投稿

エンドポイントの設計に落とし込んでいく

以下の設計原則に沿ってエンドポイントを設計しましょう。

  1. 人間が読んで機能が類推しやすいURL

    以下のような名前のエンドポイントを作ってしまうと、クライアントの実装者が見ても直感的に何をするためのAPIか分からずに使いづらいです
    https://api.example.com/ssddss/zzzza

    以下のように操作するエンティティが何であるのかわかりやすいURL設計にしましょう
    https://api.example.com/items
    https://api.example.com/posts

  2. データ構造が理解しやすいURL

    データ構造が理解しやすいURLを表現するようにしましょう。例えば「投稿」と「コメント」は必ず1対多の親子関係になるので、以下のようにネストして表現するとわかりやすいです。
    https://api.example.com/posts/100/comments/200

  3. ルールが統一されたURL

    特にパラメータのルールは統一させることを意識しましょう。例えば以下のようなエンドポイントが混在していれば、統一感がなく非常にわかりにくいAPIになります。
    https://api.example.com/posts?id=100(投稿の詳細の取得)
    https://api.example.com/posts/100/comments(コメントの一覧取得)

  4. 名詞のみで構成されたURL

    以下のようにURLに動詞を含めないようにしましょう。
    https://api.example.com/createUser

    リソース名となる名詞のみで構成して、その振る舞いはエンドポイント名ではなくメソッドで表現します。

  5. サーバー側のアーキテクチャが反映されていないURL

    クライアントがAPIで実装を行う際に、サーバー側のアーキテクチャが何であるかを理解する必要はありません。例えば以下のようなエンドポイントを作ると、単純に余計な情報をクライアントに与えるだけになってしまいます。

    REST APIとしてクライアントに与えるべき情報が最低限になっているかつ、その抽象度がブレていないAPIがきれいな設計のAPIです
    https://api.example.com/dynamodb/100

エンドポイントの設計例

例えばそれぞれの機能に対して、以下のように原則に基づいてエンドポイントを設計しました。

機能

エンドポイント

ユーザの登録

/users

ユーザの更新

/users

記事の投稿

/posts

記事の一覧の取得

/posts

記事の詳細の取得

/posts/{postid}

記事に紐づくコメントの一覧取得

/posts/{postid}/comments

コメントの詳細の取得

/posts/{postid}/comments/{commentid}

コメントの投稿

/posts/{postid}/comments

HTTPメソッド

エンドポイントを設計すれば同時にHTTPメソッドもエンドポイントに対して割り当てる必要があります。エンドポイントが操作するものの対象(リソース)を定義するのに対してHTTPメソッドはリソースに対する操作方法を定義します。

基本的には以下の役割分担で必要なメソッドをエンドポイントに割り当てていきます。

メソッド名

役割

POST

リソースの新規作成

PUT

リソースの更新

GET

リソースの取得

DELETE

リソースの削除

PATCH

リソースの部分更新

HTTPメソッドも組み合わせた設計例

それぞれのメソッドごとの役割とエンドポイントを組み合わせると以下のような設計が考えられます。この様にメソッドとエンドポイントで1つずつの機能を表現しましょう。

機能

エンドポイント

HTTPメソッド

ユーザの登録

/users

POST

ユーザの更新

/users/{userid}

PUT

記事の投稿

/posts

POST

記事の一覧の取得

/posts

GET

記事の詳細の取得

/posts/{postid}

GET

記事に紐づくコメントの一覧取得

/posts/{postid}/comments

GET

コメントの詳細の取得

/posts/{postid}/comments/{commentid}

GET

コメントの投稿

/posts/{postid}/comments

POST

リクエストパラメータの設計

メソッドとエンドポイントが決まれば、それぞれのリクエストパラメータを設計します。例えばPOSTであれば、新規作成するためのデータはクライアント側で定義する必要があります。

  • Bodyパタメータ

    HTTPリクエストのBodyにJSONなどで登録したデータを指定する方法です。主にPOSTとPUTメソッドで指定されます。

    $ curl --location --request POST '<https://example.com/posts>' \\
    --header 'Content-Type: application/json' \\
    --data-raw '{
      "tite": "記事タイトル",
      "imageUrl": "<http://example.com>",
      "content": "本文本文"
    }'
    
  • Pathパラメータ

    URLパスの一部を変数として扱うパラメータのして方法です。主にそのエンティティを一意に確定させる主キーをPathパラメータとして指定します。以下の例では123が投稿IDを示しており、該当の投稿を更新しようとしています。主にPUT, PATCH, DELETEメソッドで指定されます。

    $ curl --location --request PUT '<https://example.com/posts/123>' \\
    --header 'Content-Type: application/json' \\
    --data-raw '{
      "tite": "記事タイトル2",
      "imageUrl": "<http://example.com>",
      "content": "本文本文2"
    }'
    
  • Querystringパラメータ

    URLの末尾に ?foo=bar のような形式で付与するパラメータです。主にGETメソッドで取得した結果をフィルターしたいような場合に使います。

    • 検索ワードを指定する
    • 一覧取得の際の表示件数
    • 一覧取得の際の取得開始位置
    $ curl -XGET '<https://example.com/posts?paged=3&num=30>
    
    $ curl -XGET '<https://example.com/posts/100/comments?num=30>
    

ヘッダを使ったリクエストパラメータ

認証・認可のあるAPIへのリクエストは、 Authorization ヘッダにトークンをセットしてリクエストするケースがほとんどでしょう。(OAuthの仕様)

$ curl --location --request PUT '<https://example.com/products/cd0ddacf-b51e-48e8-a07d-ad514eae7f83>' \\
--header 'Content-Type: application/json' \\
--header 'Authorization: bearer xxxxxxxxxxxxxxxxxxxxxxxxx'
--data-raw '{
  "name": "あああああいいい",
  "imageUrl": "<http://example.com>",
  "price": "3000",
  "description": "testtest"
}'

レスポンスデータの設計

エンドポイントとHTTPメソッド、リクエストパラメータによるリクエストを受け取ったらサーバー側で処理を行った上で、レスポンスを返す必要があります。このレスポンスも必要な情報をREST APIの設計指針に基づいて設計する必要があります。

ステータスコード

ステータスコードは特定の HTTP リクエストが正常に完了したどうかをレスポンスに示します。 5 つのクラスに分類されています。

  1. 情報レスポンス (100199)
  2. 成功レスポンス (200299)
  3. リダイレクトメッセージ (300399)
  4. クライアントエラーレスポンス (400499)
  5. サーバーエラーレスポンス (500599)

よく使用されるステータスコードには以下のようなものがあります。

ステータスコード

意味

200

リクエストが成功したことを示します。成功が意味することは、 HTTP メソッドにより異なります。

GET: リソースが読み込まれ、メッセージ本文で転送された。

PUT やDELETE: 操作の結果を表すリソースがメッセージ本文で送信される。

201

リクエストは成功し、その結果新たなリソースが作成されたことを示します。 POST で新規にデータが作成された場合はこのステータスコードを使用します。

202

リクエストは受理されたが、まだ実行されていないことを示します。主に非同期処理を扱う際に使用するレスポンスです。

301

リダイレクトの際のレスポンスステータスです。リクエストされたリソースの URL が永遠に変更されたことを示します。レスポンスで新しい URL が与えられます。

302

リダイレクトの際のレスポンスステータスです。リクエストされたリソースの URI が 一時的に変更されたことを示します。

400

リクエストのパラメータが仕様通りでないため、リクエストが処理できないことを示します。

401

認証が通らないことを示します。

403

リソースへのアクセス権がなくサーバーがアクセスを拒否していることを示します。

404

存在しないリソースへアクセスしていることを示しています。

500

サーバー側で何かしらの原因でエラーが発生していることを示しています。

正常系のレスポンス

処理を受け取って正しく処理が完了したら200系のレスポンスを返却しましょう。例えばユーザの一覧をGETで取得するAPIで正しくデータが取得できれば、200レスポンスと取得したデータをレスポンスボディで返却します。

$ GET <https://example.com/users>

------ レスポンスヘッダ ------
HTTP/2 200 
date: Mon, 02 May 2022 09:39:09 GMT
content-type: application/json; charset=utf-8
content-length: 996

------ レスポンスbody ------
{
  "page": 1,
  "per_page": 6,
  "total": 12,
  "total_pages": 2,
  "data": [
    {
      "id": 1,
      "email": "george.bluth@reqres.in",
      "first_name": "George",
      "last_name": "Bluth",
      "avatar": "<https://reqres.in/img/faces/1-image.jpg>"
    },
    {
      "id": 2,
      "email": "janet.weaver@reqres.in",
      "first_name": "Janet",
      "last_name": "Weaver",
      "avatar": "<https://reqres.in/img/faces/2-image.jpg>"
    }

エラー系のレスポンス

エラーが発生した場合は400 - 500までのレスポンスから状況に合わせた適切なステータスコードを返却しましょう。

例えばバリデーションに引っかかった場合はリクエストパラメータが仕様どおりでないということなので400エラーを返すべきでしょう。その際にエラーの詳細をBodyパラメータとして返すとより親切なAPIになります。

$ POST <https://exmaple.com/users>

------ レスポンスヘッダ ------
HTTP/2 400 

------ レスポンスbody ------
{
  "error_message": "nameパラメータが指定されていません。"
}

サーバー側でExceptionが発生してエラーの詳細が特定できない場合などは500エラーを返しましょう。

$ POST <https://exmaple.com/users>

------ レスポンスヘッダ ------
HTTP/2 500 

------ レスポンスbody ------
{
  "error_message": "予期せぬエラーが発生しました。管理者に連絡してください。"
}

まとめ

この記事では、REST APIの設計における基本原則について解説しました。エンドポイントの設計には、直感的で理解しやすいURL設計や、一貫性のあるリクエスト方法が重要です。また、HTTPメソッドやステータスコードの正しい使用が、APIの使いやすさや拡張性を高めます。エラーハンドリングや適切なレスポンスも考慮し、クライアントにとって分かりやすいAPIを提供することが重要になるでしょう。

Written by
CEO

堀家 隆宏

Takahiro Horike

  • Facebook->
  • X->
  • GitHub->

Share

Facebook->X->
Back
to list
<-