はじめに
これまで業務でのAPI設計を、基本REST APIで実装してきましたが、何かと聞かれたらすごいフワッとしか答えられないことに気付き、さすがにまずいと思ったので勉強のために今回の記事を書きます。
今回の目的
REST APIについて簡単にまとめた記事になります。
REST APIとは?
まず、RESTとはWebサービスの設計に関する原則的な考え方を指すものです。
要は、サーバやコンピュータなどの、複数のアプリケーションを連携させるのに適した原則のことです。
アプリケーション間の連携をしてくれる役割を持つAPI(Application Programming Interface)をこの原則に沿って作成したものが、REST APIになります。
RESTの6つの基本原則
では、そのRESTの6つの原則というものがあります。1つずつ見ていきます。
1. クライアント・サーバーアーキテクチャ
クライアントとサーバーのコンピュータは分離しようという考え方です。これは、役割を明確に分離することで、システムの管理と拡張が容易になります。
- クライアント:ユーザーインターフェースとユーザー体験を管理する。リクエストをサーバーに送信し、レスポンスを受け取って表示する役割。
- サーバ:ビジネスロジックとデータストレージを管理する。クライアントのリクエストを処理し、必要なデータを提供する役割。
現在では、当たり前のように使っている構成ですね。RESTでは、大前提の考え方になります。
2. ステートレス
各リクエストは自己完結型であり、サーバはクライアントの要求をそのリクエストのみで解釈できる必要がある。という考え方です。
- 自己完結型リクエスト:クライアントからの各リクエストは、それ自体に必要なすべての情報を含んでいます。例えば、認証情報、リクエストのコンテキストなど。
クライアントは、サーバの状態に依存してはならず、「Stateless(状態を持たない)」であるべきということです。
サーバー側ではセッション状態を保持せず、各リクエストが独立して処理されることで、システムの拡張性が向上します。
このステートレス性により、サーバーは各リクエストを独立して処理できるため、システムの複雑さが減少し、障害対応が容易になります。
3. キャッシュ可能
サーバは、レスポンスにキャッシュ可能性を明示し、クライアントまたは中間キャッシュサーバーがレスポンスを保存して再利用できるようにするべき、という考え方です。
クライアントはキャッシュされたデータを再利用することで、サーバーへのリクエスト回数を減らし、レスポンス時間を短縮できます。具体的には、レスポンスにはキャッシュ制御ヘッダー(例:Cache-Control、Expires、ETag)を含め、キャッシュ可能性とキャッシュの期間を指定します。
キャッシュを行うことで、ネットワークの負荷を下げ、通信を効率化できるメリットがあります。
4. 統一インターフェース
システムへのアクセスを行うインターフェース設計を一貫性のあるものにすることで、システム全体の理解と使用が容易にさせる。という考え方です。
インターフェースとは、システムとやりとりをする窓口のことです。
各リソースは一意のURI(Uniform Resource Identifier)で識別されます。例えば、特定のユーザーのデータは https://example.com/users/123 のようなURIで表現されます。この例のように、URIはリソースの場所を明確に示す書き方をします。
また、RESTは、リソースの操作に対して標準的なHTTPメソッドを使用します。これにより、リソースに対する操作が直感的に行えます。
- GET: リソースの取得(例: ユーザー情報を取得)
- POST: 新しいリソースの作成(例: 新しいユーザーを作成)
- PUT: 既存のリソースの更新(例: ユーザー情報を更新)
- DELETE: リソースの削除(例: ユーザーを削除)
各メッセージ(リクエストおよびレスポンス)は、その目的と形式を明示的に示します。例えば、リクエストにはヘッダー情報が含まれ、どの操作が行われるのか、どのデータ形式が使用されるのかが明確に記述されます。レスポンスも同様に、ステータスコードやヘッダー情報を通して、リクエストの結果がわかりやすく示されます。
5. 階層システム
システムの構成要素(コンポーネント)を、階層的に構成し、セキュリティとスケーラビリティを向上させるアーキテクチャにする、という考え方です。
先ほど、RESTではクライアントとサーバーの分離が前提になっているという話をしました。この2層に加えて、ゲートウェイ、プロキシ、ロードバランサーなどの中間層を作ります。この中間層を介して、サーバにアクセスします。この中間層がそれぞれ、セキュリティ、負荷分散、キャッシングなどの役割を担ってくれます。
このような階層システムにすることで、異なる層が独立して管理されるため、システム全体の柔軟性と拡張性が高まります。
6. コードオンデマンド(オプション)
必要に応じて、クライアント側で実行できるスクリプトをサーバーから返す、という考え方です。
クライアント側で実行できるスクリプトを用意することで、クライアントの実装コストを下げることができます。
具体的なシナリオとしては、ウェブアプリケーションで、特定のユーザーアクションに応じて追加の機能を提供するJavaScriptコードをサーバーからダウンロードする、などです。
コードオンデマンドはRESTの原則の中でもオプションとされています。つまり、必須ではないが、適用することでクライアントアプリケーションに大きな利点をもたらす可能性があるものです。
HTTPメソッド
REST APIでは、リソースの操作に対して標準的なHTTPメソッドを使用します。以下に主要なHTTPメソッドを紹介します。
HTTPメソッドの紹介
- GET: データの取得に使用されます。
- POST: データを登録する際に使用されます。特に新しいデータを作成するために使用されます。
- PUT: データを登録する際に使用されます。特に既存のデータを更新するために使用されます。
- DELETE: データを削除するために使用されます。
- PATCH: 既存のリソースの部分的な更新に使用されます。
POSTとPUTについて
どちらもリソースの新規作成や更新の際に使用されますが、違いとして対象の指定方法が異なります。
- POST:登録するデータの識別番号を、データを受け取ったアプリケーション側が発行します。例:'api/user' のようにユーザー情報の新規作成を行うと、新たに発行した一意の識別情報 'user/123' を送り返します。
- PUT:登録を要求する側が一意の識別情報(例:'api/user/123')を指定します。
違いとして、PUTの場合は、依頼される側のアプリケーションのリソースの識別体系を事前に知っている必要があるということです。(POSTに比べて、PUTの方は結合が密になりやすい。)
ステータスコード
REST APIでは、HTTPステータスコードを使用してリクエストの結果を表現します。以下に主要なステータスコードを紹介します。
200 OK: リクエストが正常に処理された。
201 Created: リソースが新しく作成された。
400 Bad Request: クライアント側のエラー。
404 Not Found: リソースが見つからない。
500 Internal Server Error: サーバー側のエラー。
RESTfulなエンドポイント設計
RESTfulとは、RESTに厳密に従っている、ということです。また、エンドポイントとは、APIにアクセスするためのURIのことです。
エンドポイントの例:https://qiita.com/api/v2/users/ta_charlie
RESTfulなエンドポイント設計を作るために大切な事項をざっくり三つあげます。
- シンプルで直感的なURL設計
- リソースの親子関係を反映するURLを設計
- フィルタリング、ソート、ページングのためのクエリパラメータの使用
以上三つを踏まえたURIの例を以下に示します。
https://example.com/users/123/posts?sort=date&page=2
上記のURIを見てみると、まず、'/users/123/posts'この箇所を見てみたときに、直感的に「指定した ID=123 ユーザーの投稿情報を見たいんだな」というのがわかります。また、投稿情報(posts)の親がユーザー(users)なんだというのもわかります。
’?sort=date&page=2’ の部分では、日付でソートし、ページングも行っています。
APIの認証と認可について
REST APIにおける認証と認可は、セキュリティを確保するために非常に重要です。ここでは、認証と認可の違い、そして一般的な認証手段について説明します。
その前に、認証認可について少し説明します。
認証について
認証はユーザー自体の確認を行うプロセスです。ユーザーが誰であるかを確認し、正当なアクセスであることをチェックします。
認可について
認可はユーザーの権限を確認するプロセスです。認証されたユーザーが特定のリソースや操作に対して適切な権限を持っているかを確認します。(管理者か、一般ユーザーかなどの権限を確認)
一般的な認証手法
OAuth:リソースを管理するサーバーに対してユーザーのアクセスを許可するために、該当ユーザーが偽物ではなく本物であることを確かめる必要があります。そのために、証明書的な役割を持つ「アクセストークン」というものを利用します。この「アクセストークン」を発行するための業界標準プロトコルが「OAuth」です。
下記に大変わかりやすい記事があるのでこちらをぜひ参考にしてください。
JWT (JSON Web Token):認証情報をJSON形式で表現したトークンを使用し、サーバーとクライアント間で安全にデータを転送します。先ほどのOAuthのアクセストークン取得のためにJWTが利用されることもあります。
以下参照
APIキー:クライアントに対して発行される一意のキーを使用して認証を行います。トークンとは違います。API キーは、ランダムに生成されたアルファベットと数字の文字で構成されています。API サーバーは、固有の API キーを使用してリクエスターの信頼性を検証したりすることができます。キーが一致しない場合は、API呼び出しを拒否します。
トークンとの違いとして、
APIキーは通常、呼び出し元のアプリケーションがデプロイされている特定のサーバーに関連付けられています。アプリケーションが APIリクエストを行うと、サーバーは APIキーによって呼び出し元のアプリケーションを識別します。
対照的に、トークンは特定のユーザーを識別する包括的なデータを含むコードの文字列です。APIトークンには、特定のユーザーに付与されるアクセスの範囲も含まれます。これにより、サーバーは呼び出し元ユーザーのリクエストを認証し、APIの使用範囲を検証できます。
つまり、APIキーは、呼び出したいAPIサーバはどれか?という情報のみ含まれており、対してトークンは、そのトークン自体にユーザーの情報が詰め込まれているものということになります。
重量感で言うと、トークンの方が重いイメージです。
まとめ
この記事では、REST APIについて学んだことを書きました。
これまでなんとなく行っていたAPI開発も調べてみれば認証のことなど、まだまだ知らないことだらけです。
今後また何か新たな知識を得たタイミングでREST APIについて書いていこうと思います。
参照
書籍:「現場で役立つ システム設計の原則」