Web APIとREST APIとは
WebAPIとは「HTTPプロトコルを利用してネットワーク越しに呼び出すAPI」です。APIとは”Application Programming Interface”の略で、ソフトウェアの機能はわかっているけれども中身の動作は詳しくわからない機能の塊を外部から呼び出すための仕組みです。プロトコルとしてHTTPを使うため、そのエンドポイントはURLによって指定されることになります。
REST APIとはWeb APIを使ってデータをやり取りするための規約の一つです。URLですべてのリソース(データ)を表現し、GETやPOSTといったメソッドでリソースへの操作方法をしていします。クライアントからリクエストを送信するとその応答をJSONやプレーンテキスト、XMLなどで受け取ることが出来ます。
例:ユーザAPI( https://reqres.in/api/users )
RestにおけるエンドポイントとHTTPメソッドの設計
まずはオーソドックスなブログ投稿型のアプリケーションを考えてみましょう
必要な機能のリストアップ
まずはAPIとしてどういった機能を実装する必要があるのかをリストアップしましょう。これらをベースにしてエンドポイントと割り当てるHTTPメソッドを設計していきます設計していきます。
- ユーザの登録
- ユーザの更新
- 記事の投稿
- 記事の一覧の取得
- 記事の詳細の取得
- 記事に紐づくコメントの一覧取得
- コメントの詳細の取得
- コメントの投稿
エンドポイントの設計に落とし込んでいく
以下の設計原則に沿ってエンドポイントを設計しましょう。
- 人間が読んで機能が類推しやすいURL
以下のような名前のエンドポイントを作ってしまうと、クライアントの実装者が見ても直感的に何をするためのAPIか分からずに使いづらいです
https://api.example.com/ssddss/zzzza以下のように操作するエンティティが何であるのかわかりやすいURL設計にしましょう
https://api.example.com/items
https://api.example.com/posts - データ構造が理解しやすいURL
データ構造が理解しやすいURLを表現するようにしましょう。例えば「投稿」と「コメント」は必ず1対多の親子関係になるので、以下のようにネストして表現するとわかりやすいです。
https://api.example.com/posts/100/comments/200 - ルールが統一されたURL
特にパラメータのルールは統一させることを意識しましょう。例えば以下のようなエンドポイントが混在していれば、統一感がなく非常にわかりにくいAPIになります。
https://api.example.com/posts?id=100(投稿の詳細の取得)
https://api.example.com/posts/100/comments(コメントの一覧取得) - 名詞のみで構成されたURL
以下のようにURLに動詞を含めないようにしましょう。
https://api.example.com/createUserリソース名となる名詞のみで構成して、その振る舞いはエンドポイント名ではなくメソッドで表現します。
- サーバー側のアーキテクチャが反映されていない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 つのクラスに分類されています。
- 情報レスポンス (
100
–199
) - 成功レスポンス (
200
–299
) - リダイレクトメッセージ (
300
–399
) - クライアントエラーレスポンス (
400
–499
) - サーバーエラーレスポンス (
500
–599
)
よく使用されるステータスコードには以下のようなものがあります。
ステータスコード | 意味 |
---|---|
200 | リクエストが成功したことを示します。成功が意味することは、 HTTP メソッドにより異なります。 |
• | |
• | |
201 | リクエストは成功し、その結果新たなリソースが作成されたことを示します。 |
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を提供することが重要になるでしょう。