Webアプリケーションの基本
この講座では、Webアプリケーションの基本について学びます。
- Webアプリケーションの概要と特徴
- HTTPプロトコルの仕組み(リクエストとレスポンス)
- HTTPメソッド、ステータスコード、ヘッダ、ボディ
- APIとJSON形式のデータ
- RESTful APIの設計原則
- URLの構造とルーティング
1. Webアプリケーションとは
1.1 Webアプリケーションの概要
Webアプリケーションとは、Webブラウザを介して主にインターネット上で利用されるアプリケーションです。従来のWordやExcelのようなデスクトップアプリケーションや、スマートフォンで動作するネイティブアプリケーションは、各端末にインストールして使用します。それに対してWebアプリケーションはサーバ上で主要な処理が行われ、ブラウザ上でユーザ操作が行われる点が異なります。
Webアプリケーションでは、ユーザはブラウザを介してアプリケーションにアクセスします。ブラウザは、ユーザとのインタフェースとなる画面の表示や、入力データの受付などを行います。ブラウザ上で動作し、ユーザとの直接的なやり取りを担当する部分をフロントエンドと呼びます。
アプリケーションのメインとなる多くの処理は、Webサーバと呼ばれるサーバ上で行われます。例えば、ユーザの入力データに対する計算処理や、データベースの操作など、裏側の処理を担当します。これらのサーバ上で動作する部分をバックエンドと呼びます。
ブラウザとWebサーバの間の通信は、原則としてインターネットを経由し、HTTPというプロトコルを用いて行われます。
1.2 Webアプリケーションの特徴
Webアプリケーションの特徴として、ここでは主に3つを紹介します。
ユーザが気軽に利用できる
1つ目は「ユーザが気軽に利用できる」という点です。ユーザは端末にアプリケーションをインストールせずに、ブラウザ上のみで利用できます。これにより、ユーザの利用のハードルを下げ、多くのユーザに普及しやすくなります。
処理をサーバに集約できる
2つ目は「処理をサーバに集約できる」という点です。ユーザの端末のスペックを意識せず、サーバ側で複雑な処理を実装できます。また、アプリケーションの更新やOS・ミドルウェアのアップデートなどのメンテナンスも、サーバ上で一元的に行うことができます。
技術が標準化されている
3つ目は「技術が標準化されている」という点です。フロントエンドはHTML、CSS、JavaScriptといった標準技術で開発され、通信にはHTTPが利用されます。バックエンドでも、PythonやAWSなどの広く使われる技術が採用されます。これにより、開発者はシステムごとに特別な技術を学ぶ必要がなく、効率的に開発を進められます。
2. HTTPとは
2.1 HTTPの概要
HTTP(HyperText Transfer Protocol)は、インターネット上でデータをやり取りするためのプロトコル、いわゆる通信規約です。WebブラウザとWebサーバ間でHTMLや画像などのリソースを転送するために広く使用されています。
例えば、ブラウザでWebサイトを見ようとしたとき、URLの先頭にhttpやhttpsとついていると思います。これは、HTTPプロトコルを利用して通信(Webサイトの表示)を行っていることを示しています。なお、HTTPSはHTTPに暗号化の要素を加えてセキュリティ機能を高めたもので、HTTPの拡張プロトコルです。
HTTPプロトコルでは、クライアント(通常はWebブラウザ)が、Webサーバに対してリクエストを送信し、サーバがそれに対してレスポンスを返す形で通信が行われます。
HTTPリクエストとレスポンスの流れを図に示します。
sequenceDiagram
participant クライアント
participant サーバ
クライアント->>サーバ: HTTPリクエスト(メソッド, URL, ヘッダ, ボディ)
サーバ->>クライアント: HTTPレスポンス(ステータスコード, ヘッダ, ボディ)
2.2 リクエスト
リクエストは、クライアントからサーバに対して行う処理の依頼です。リクエストはメソッド、パス、ヘッダ、ボディの4つの要素で構成されています。
メソッド
メソッドは、クライアントがサーバに対して「何をしてほしいのか」という処理の種類を表す要素です。たとえば、データを取得したい場合はGET、新しいデータを作成したい場合はPOSTを指定します。メソッドについては、次のセクションで詳しく説明します。
GET /users HTTP/1.1
この例では、メソッドとしてGETが指定されています。これはサーバに対して「ユーザのデータを取得してほしい」というリクエストを表しています。なお、末尾のHTTP/1.1は使用するHTTPプロトコルのバージョンを示しています。HTTP/1.1は現在最も広く使われているバージョンで、後継のHTTP/2やHTTP/3も普及が進んでいますが、基本的な仕組み(メソッド、パス、ヘッダ、ボディなど)はバージョンが変わっても共通です。
パス
パスは、サーバ上のどのリソースに対してリクエストを送るかを示す要素です。たとえば、/usersというパスであればユーザの一覧リソースを、/users/1であればIDが1のユーザリソースを指定していることになります。パスによって、サーバ側でどの処理を実行するかが決まります。
GET /users/1 HTTP/1.1
この例では、パスとして/users/1が指定されています。これはサーバ上の「IDが1のユーザ」というリソースを対象としたリクエストを表しています。
ヘッダ
ヘッダは、リクエストに付随する補足情報を格納する要素です。たとえば、送信するデータの形式を示すContent-Type(application/jsonなど)や、認証に使用するトークン情報(Authorization)などが含まれます。ヘッダはキーと値のペアで構成され、複数のヘッダを同時に送信できます。
Content-Type: application/json
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
この例では、2つのヘッダが指定されています。Content-TypeでリクエストボディのデータがJSON形式であることを示し、Authorizationで認証用のトークンをサーバに送信しています。
ボディ
ボディは、クライアントからサーバに送信するデータそのものを格納する領域です。たとえば、新しいユーザを登録する際には、ユーザ名やメールアドレスなどのデータをボディに含めて送信します。なお、データの取得(GET)や削除(DELETE)など、送信するデータがないリクエストではボディは省略されます。
{
"name": "田中太郎",
"email": "tanaka@example.com"
}
この例では、新しいユーザを作成するリクエストのボディとして、ユーザ名とメールアドレスをJSON形式で送信しています。
ここまで紹介した4つの要素を組み合わせると、実際のHTTPリクエストは以下のような形で送信されます。
POST /users HTTP/1.1
Content-Type: application/json
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
{
"name": "田中太郎",
"email": "tanaka@example.com"
}
1行目にメソッド(POST)とパス(/users)が記載され、続いてヘッダ(Content-TypeとAuthorization)が並び、空行を挟んだ後にボディ(JSON形式のユーザデータ)が続きます。このように、HTTPリクエストはメソッド・パス・ヘッダ・ボディが一つのまとまりとしてサーバに送信されます。
リクエストの構成要素をまとめると以下のとおりです。
| 要素 | 役割 |
|---|---|
| メソッド | 処理の種類を指定する(GET、POST、PUT、DELETEなど) |
| パス | 対象リソースの位置を指定する(/users、/users/1など) |
| ヘッダ | データ形式や認証情報などの補足情報を付与する |
| ボディ | サーバに送信するデータを格納する(省略される場合もある) |
2.3 レスポンス
レスポンスは、Webサーバがクライアントに返却する処理の結果です。レスポンスはステータスコード、ヘッダ、ボディの3つの要素で構成されています。
ステータスコード
ステータスコードは、サーバがリクエストをどのように処理したかを示す3桁の数値コードです。たとえば、200はリクエストが正常に処理されたことを、404は指定されたリソースが見つからなかったことを表します。ステータスコードについては、後のセクションで詳しく説明します。
HTTP/1.1 200 OK
この例では、ステータスコード200が返されており、リクエストが正常に処理されたことを示しています。
ヘッダ
ヘッダは、レスポンスに付随する補足情報を格納する要素です。たとえば、返却するデータの形式を示すContent-Type(application/jsonやtext/htmlなど)や、キャッシュの制御に関する情報などが含まれます。リクエストのヘッダと同様に、キーと値のペアで構成されます。
Content-Type: application/json
Content-Length: 64
この例では、レスポンスのデータがJSON形式であること(Content-Type)と、データのサイズが64バイトであること(Content-Length)をヘッダで示しています。
ボディ
ボディは、サーバからクライアントに返却するデータそのものを格納する領域です。たとえば、ユーザ情報を取得するリクエストに対しては、ユーザのデータがJSON形式などでボディに格納されて返されます。なお、削除処理の完了レスポンスなど、返却するデータがない場合にはボディが省略されることもあります。
{
"id": 1,
"name": "田中太郎",
"email": "tanaka@example.com"
}
この例では、IDが1のユーザ情報がJSON形式でレスポンスボディとして返されています。
ここまで紹介した3つの要素を組み合わせると、実際のHTTPレスポンスは以下のような形でクライアントに返されます。
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 64
{
"id": 1,
"name": "田中太郎",
"email": "tanaka@example.com"
}
1行目にステータスコード(200 OK)が記載され、続いてヘッダ(Content-TypeとContent-Length)が並び、空行を挟んだ後にボディ(JSON形式のユーザデータ)が続きます。このように、HTTPレスポンスはステータスコード・ヘッダ・ボディが一つのまとまりとしてクライアントに返されます。
レスポンスの構成要素をまとめると以下のとおりです。
| 要素 | 役割 |
|---|---|
| ステータスコード | 処理結果を3桁の数値で示す(200、404など) |
| ヘッダ | データ形式やキャッシュ方針などの補足情報を付与する |
| ボディ | クライアントに返却するデータを格納する(省略される場合もある) |
3. HTTPメソッド
HTTPリクエストにおけるメソッドとは、リクエストが「何をしたいのか」という操作の種類を示すものです。代表的なメソッドには、GET、POST、PUT、DELETEがあります。
3.1 代表的なHTTPメソッドの種類
GET
GETメソッドは、サーバからリソースやデータを取得するときに使用されます。例えば、ユーザの一覧を取得したり、特定のIDを持つユーザデータを取得する場合などに利用されます。
GET /users HTTP/1.1
この例では、/usersに対してGETリクエストを送信しています。サーバはユーザの一覧データをレスポンスとして返します。
POST
POSTメソッドは、主にリソースやデータを作成するときに利用されます。新しいユーザの登録やタスクの作成を行う場合などに使用されます。作成するデータはリクエストのボディに格納してサーバに送信されます。
POST /users HTTP/1.1
Content-Type: application/json
{"name": "田中太郎", "email": "tanaka@example.com"}
この例では、/usersに対してPOSTリクエストを送信し、ボディに新しいユーザの情報をJSON形式で含めています。サーバはこのデータをもとに新しいユーザを作成します。
PUT
PUTメソッドは、特定のリソースやデータを更新するときに利用されます。例えば、既存のユーザ情報を変更したい場合などに使用されます。POSTと同様に、データをリクエストのボディに含めてサーバに送信します。
PUT /users/1 HTTP/1.1
Content-Type: application/json
{"name": "田中次郎", "email": "jiro@example.com"}
この例では、/users/1(IDが1のユーザ)に対してPUTリクエストを送信し、ボディに更新後のデータを含めています。サーバはIDが1のユーザの情報を、送信されたデータで更新します。
DELETE
DELETEメソッドは、特定のリソースやデータを削除する場合に利用されます。例えば、登録済みのタスクを削除したい場合などに使用されます。
DELETE /users/1 HTTP/1.1
この例では、/users/1(IDが1のユーザ)に対してDELETEリクエストを送信しています。サーバはIDが1のユーザを削除します。DELETEリクエストでは、通常ボディは含めません。
| 💡 ポイント |
|---|
| リクエストのパスとHTTPメソッドの組み合わせにより、サーバ側で実行される処理の振り分けが行われます。この仕組みをルーティングと呼びます。 |
HTTPメソッドの一覧をまとめると以下のとおりです。
| メソッド | 操作 | ボディ | リクエスト例 |
|---|---|---|---|
GET |
データの取得 | なし | GET /users |
POST |
データの作成 | あり | POST /users |
PUT |
データの更新 | あり | PUT /users/1 |
DELETE |
データの削除 | なし | DELETE /users/1 |
4. ステータスコード
ステータスコードは、HTTPのレスポンスにおいてサーバ側の処理結果を示すために定義されているコードで、レスポンスの一部としてクライアントに返却されます。クライアントではステータスコードをもとに、適切なエラーハンドリングなどを実装することができます。
4.1 2xx(成功)
2から始まるステータスコードは、正常な状態を示す番号体系です。
200 OK
リクエストが正常に処理されたことを表すステータスコードです。最も基本的な成功レスポンスで、GETリクエストでデータの取得に成功した場合や、PUTリクエストでデータの更新に成功した場合などに返されます。
HTTP/1.1 200 OK
Content-Type: application/json
{"id": 1, "name": "田中太郎", "email": "tanaka@example.com"}
この例では、ユーザ情報の取得リクエストに対して200 OKが返され、ボディにユーザのデータが含まれています。
201 Created
リソースの作成が正常に完了したことを示すステータスコードです。POSTメソッドによって新しいデータが作成された場合に返されます。
HTTP/1.1 201 Created
Content-Type: application/json
{"id": 2, "name": "鈴木花子", "email": "hanako@example.com"}
この例では、新しいユーザの作成リクエストに対して201 Createdが返され、ボディに作成されたユーザのデータ(自動採番されたIDを含む)が含まれています。
4.2 4xx(クライアントエラー)
4から始まるステータスコードは、クライアント側に原因があるエラーを示します。
400 Bad Request
クライアントからのリクエストが不正である場合に返されるステータスコードです。リクエストの形式が正しくない場合や、必須のパラメータが不足している場合などが該当します。
HTTP/1.1 400 Bad Request
Content-Type: application/json
{"error": "name is required"}
この例では、必須パラメータであるnameが含まれていないリクエストに対して400 Bad Requestが返され、ボディに不足しているパラメータの情報が含まれています。
403 Forbidden
リソースへのアクセスが禁止されている場合に返されるステータスコードです。認証の成否に関わらず、権限がないユーザがリソースにアクセスを試みたときに返されます。
HTTP/1.1 403 Forbidden
Content-Type: application/json
{"error": "You do not have permission to access this resource"}
この例では、権限のないリソースへのアクセスに対して403 Forbiddenが返され、ボディにアクセスが拒否された理由が含まれています。
404 Not Found
指定されたリソースがサーバ上に存在しない場合に返されるステータスコードです。多くの場合、URLのパスが誤っていることが原因です。
HTTP/1.1 404 Not Found
Content-Type: application/json
{"error": "User not found"}
この例では、存在しないユーザへのリクエストに対して404 Not Foundが返され、ボディにリソースが見つからなかった旨が含まれています。
4.3 5xx(サーバエラー)
5から始まるステータスコードは、サーバ側に原因があるエラーを示します。
500 Internal Server Error
サーバ内部で予期しないエラーが発生した場合に返されるステータスコードです。サーバの設定ミスやアプリケーションのバグなどが主な原因です。
HTTP/1.1 500 Internal Server Error
Content-Type: application/json
{"error": "Internal Server Error"}
この例では、サーバ内部でエラーが発生し、500 Internal Server Errorが返されています。クライアント側では原因を特定できないため、サーバ側のログを確認する必要があります。
503 Service Unavailable
サーバが一時的に利用できない場合に返されるステータスコードです。サーバのメンテナンスや過負荷、バックエンドサービスの停止などが該当します。
HTTP/1.1 503 Service Unavailable
Content-Type: application/json
{"error": "Service temporarily unavailable"}
この例では、サーバが一時的に利用できない状態であることを示す503 Service Unavailableが返されています。通常、時間をおいて再度リクエストを送ることで解決します。
| 📝 ステータスコードの活用 |
|---|
| ステータスコードを適切に使用することで、クライアントとサーバが共通の認識を持ち、処理結果を効果的に伝えることが可能になります。これにより、システムが期待どおりに動作しているか、またはどの部分で問題が発生しているかを確認することに繋がります。 |
ステータスコードの一覧をまとめると以下のとおりです。
| ステータスコード | 分類 | 説明 |
|---|---|---|
200 OK |
成功 | リクエストが正常に処理された |
201 Created |
成功 | 新しいリソースの作成が完了した |
400 Bad Request |
クライアントエラー | リクエストの形式が不正、または必須パラメータが不足している |
403 Forbidden |
クライアントエラー | リソースへのアクセス権限がない |
404 Not Found |
クライアントエラー | 指定されたリソースが存在しない |
500 Internal Server Error |
サーバエラー | サーバ内部で予期しないエラーが発生した |
503 Service Unavailable |
サーバエラー | サーバが一時的に利用できない |
5. ヘッダ
ヘッダとは、HTTPリクエストおよびレスポンスに含まれる要素であり、クライアントとサーバ間で必要な情報をやり取りするために使用されます。リクエストとレスポンスの双方でヘッダは使用されますが、それぞれに含まれるヘッダの内容は異なることが多いです。
5.1 リクエストヘッダの例
代表的なリクエストヘッダの項目をいくつか紹介します。
Content-Type
リクエストボディのデータ形式を指定するヘッダです。サーバはこのヘッダを参照して、受け取ったデータをどの形式として解釈すべきかを判断します。例えばapplication/jsonはJSON形式、text/plainはプレーンテキスト形式を表します。
JSON形式のデータを送信する場合は以下のように指定します。
Content-Type: application/json
プレーンテキストのデータを送信する場合は以下のように指定します。
Content-Type: text/plain
Authorization
認証情報を格納するヘッダです。主にユーザ認証とアクセス制御のために使用され、Bearer <token>という形式でトークンの文字列が指定されます。この形式はJWT(JSON Web Token)やOAuth 2.0などの認証方式でよく利用されます。認証が必要なAPIにリクエストを送る際は、このヘッダにトークンを含める必要があります。
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
この例では、Bearerの後にトークン文字列を指定しています。サーバはこのトークンを検証し、リクエストの送信者が正当なユーザであるかを確認します。
User-Agent
リクエストを送信しているクライアントの情報を格納するヘッダです。ブラウザの種類やバージョン、OS情報などが含まれます。サーバ側ではこの情報をもとに、アクセスログの記録やクライアントごとのレスポンスの最適化などに活用することがあります。
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36
この例では、macOS上のブラウザからリクエストが送信されていることがわかります。
Accept
クライアントが期待するレスポンスのデータ形式をサーバに伝えるヘッダです。例えばapplication/jsonが指定されている場合、サーバはJSON形式でレスポンスを返すことが期待されます。サーバが指定された形式に対応していない場合は、エラーレスポンスが返されることがあります。
Accept: application/json
この例では、クライアントがJSON形式のレスポンスを期待していることをサーバに伝えています。
カスタムヘッダ
標準的なヘッダ以外に、アプリケーション固有の情報を追加したい場合に使用されるヘッダです。X-から始まる名前で記載することが一般的ですが、X-の付与は必須ではありません。
X-Request-ID: 550e8400-e29b-41d4-a716-446655440000
この例では、リクエストを一意に識別するためのIDをカスタムヘッダとして付与しています。サーバ側でこのIDをログに記録することで、問題が発生した際にリクエストを追跡しやすくなります。
5.2 レスポンスヘッダの例
代表的なレスポンスヘッダの項目を紹介します。
ステータスラインはレスポンスの最初の行に記載され、プロトコル、ステータスコード、メッセージを示します。
以下はレスポンスヘッダの例です。
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 128
Cache-Control: max-age=3600
Server: uvicorn
Content-Type
レスポンスボディのデータ形式を示すヘッダです。クライアントはこのヘッダを参照して、受け取ったデータをどの形式として解釈すべきかを判断します。リクエストヘッダのContent-Typeと同じ名前ですが、レスポンスではサーバが返すデータの形式を示す役割を持ちます。
JSON形式のデータを返す場合は以下のように指定されます。
Content-Type: application/json
HTML形式のデータを返す場合は以下のように指定されます。
Content-Type: text/html
Content-Length
レスポンスボディのサイズをバイト数で示すヘッダです。クライアントはこの値をもとに、データの受信が完了したかどうかを判断できます。
Content-Length: 128
この例では、レスポンスボディのデータサイズが128バイトであることを示しています。
Cache-Control
コンテンツのキャッシュ方針を指定するヘッダです。たとえばmax-age=3600と指定されている場合、クライアントは3600秒(1時間)の間、同じリソースに対する再リクエストを行わずにキャッシュされたデータを使用できます。
Cache-Control: max-age=3600
この例では、クライアントに対して「このレスポンスを3600秒(1時間)キャッシュしてよい」と指示しています。キャッシュが有効な間は、同じリソースへのリクエストをサーバに送信せずにキャッシュされたデータを利用できるため、通信量を削減できます。
Server
レスポンスを送信しているサーバソフトウェアの種類を示すヘッダです。
Server: uvicorn
この例では、PythonのASGIサーバであるuvicornが使用されていることがわかります。
このセクションで紹介したヘッダの一覧をまとめると以下のとおりです。
| ヘッダ | 種類 | 説明 |
|---|---|---|
Content-Type |
リクエスト / レスポンス | ボディのデータ形式を指定する(application/jsonなど) |
Authorization |
リクエスト | 認証情報(トークン)を格納する |
User-Agent |
リクエスト | クライアントの情報(ブラウザの種類など)を格納する |
Accept |
リクエスト | クライアントが期待するレスポンスのデータ形式を指定する |
Content-Length |
レスポンス | レスポンスボディのサイズをバイト数で示す |
Cache-Control |
レスポンス | コンテンツのキャッシュ方針を指定する |
Server |
レスポンス | サーバソフトウェアの種類を示す |
6. ボディ
ボディとは、HTTP通信においてクライアントとサーバ間でやり取りされるデータそのものであり、ヘッダに記載されたContent-Typeに応じてさまざまな形式で指定することができます。
6.1 代表的なボディの種類
application/json
キーと値のペアで構成されたJSON形式のデータを送受信するために使用されます。APIの通信で最もよく使われる形式です。
{
"name": "テスト太郎",
"age": 30,
"email": "taro@example.com"
}
text/plain
単純な文字列を送信する際に使われます。
multipart/form-data
複数のデータフィールド(テキストやファイルなど)を同時に送信する際に使用されます。application/jsonでは通常テキストデータのみを扱いますが、multipart/form-dataではユーザの名前やプロフィール画像といった異なる形式のデータを一度に送信できるため、ファイルを含むデータ送信に適しています。
| 📝 その他のContent-Type |
|---|
ここで紹介した以外にも、image/jpeg(画像ファイル)、application/xml(XML形式)など、さまざまなContent-Typeが存在します。 |
ボディのデータ形式の一覧をまとめると以下のとおりです。
| Content-Type | データ形式 | 用途 |
|---|---|---|
application/json |
JSON | APIの通信で最もよく使われる形式 |
text/plain |
プレーンテキスト | 単純な文字列の送信 |
multipart/form-data |
マルチパート | ファイルを含む複数のデータフィールドの同時送信 |
7. APIとは
7.1 APIの概要
API(Application Programming Interface)は、異なるシステムの間でデータをやり取りするための仕組みです。軽量な文字データを通じてシステム間のやり取りを行います。APIを通じたやり取りは、JSON形式やXML形式などの標準的なデータ形式で行われることが多いです。JSONは人間にも読みやすく、機械にとっても効率的に処理できるため、広く採用されています。
APIを利用することで、異なるシステム間で疎結合を実現できます。疎結合とは、お互いのシステムの依存度を最小限に抑えることを意味し、一方のシステムの変更が他方に与える影響を最小限に抑えることができます。結果として、システムの保守性が向上し、新しい機能の追加や変更が容易になります。
7.2 JSONデータ形式
JSON(JavaScript Object Notation)は、APIで最も広く使われるデータ形式です。キーと値のペアでデータを表現します。
以下はJSONデータの例です。
{
"id": 1,
"title": "タスク管理APIを作る",
"completed": false,
"tags": ["Python", "FastAPI"],
"assignee": {
"name": "田中太郎",
"email": "tanaka@example.com"
}
}
JSONの特徴は以下のとおりです。
- 文字列は
""(ダブルクォート)で囲む - 数値と真偽値(
true/false)はそのまま記述する - 配列は
[]で表現する - オブジェクト(入れ子構造)は
{}で表現する
| 💡 ポイント |
|---|
Pythonでは、jsonモジュールを使ってJSON文字列とPythonの辞書型を相互に変換できます。この後学習するFastAPIでは、このJSON変換が自動的に行われるため、開発者はPythonのオブジェクトをそのまま扱えます。 |
8. URLの構造
HTTPリクエストを送信する際に指定するURLは、いくつかの要素で構成されています。
以下のURLを例に見ていきます。
http://example.com:8080/api/users
このURLを分解すると、以下の要素に分割されます。
| 要素 | 値 | 説明 |
|---|---|---|
| プロトコル | http |
通信に利用するプロトコルを表す。httpやhttpsがある |
| ホスト | example.com |
対象のサーバのドメイン名。IPアドレスも指定可能 |
| ポート | 8080 |
通信に利用するポート番号 |
| パス | /api/users |
サーバ上のリソースの位置を特定する |
ホストはサーバのドメイン名またはIPアドレスです。ローカルのサーバにアクセスする場合はlocalhostを指定します。
ポートは、通信に利用するポート番号です。HTTPではポート80、HTTPSではポート443がデフォルトで使用されます。開発中のWebアプリケーションでは、標準ポートと衝突しないよう8000や8080などのポートがよく使用されます。
パスは、サーバ上のリソースを特定するために使用されます。パスを省略した場合は「ルートパス」(/)として扱われます。/api/users/123のようにURLにパラメータを含めることもできます。
サーバ側では、パスとHTTPメソッドを組み合わせて、HTTPリクエストを適切なハンドラ関数にマッピングします。この仕組みをルーティングと呼びます。
9. RESTful APIとは
9.1 RESTful APIの概要
RESTful APIとは、APIを設計する際に広く採用されている設計原則(ルール)のことです。REST(Representational State Transfer)という設計思想に基づいて作られたAPIを、RESTful APIと呼びます。
ここまでの説明で、HTTP通信の仕組み(メソッド、パス、ステータスコード、ヘッダ、ボディ)やAPIの概念について学んできました。RESTful APIは、これらの仕組みを「どのように組み合わせてAPIを設計すべきか」を示すガイドラインです。
たとえば、タスク管理アプリのAPIを作るとき、「タスクの一覧を取得するにはどんなURLにどんなメソッドでリクエストすればいいのか」「新しいタスクを作成するにはどうすればいいのか」といった設計の指針を、RESTful APIの原則が提供してくれます。
RESTful APIは、主に以下の5つの原則で構成されています。
- クライアントとサーバの分離(Client-Server)
- 統一されたインタフェース(Uniform Interface)
- ステートレス(Stateless)
- キャッシュ可能性(Caching)
- 階層化された構造(Layered System)
それぞれの原則について、具体的な事例を交えながら説明していきます。
| 📝 設計原則の表現について |
|---|
| これらの設計原則は、書籍やWebサイトによって表現の仕方や解釈に微妙な違いが見られることがありますが、基本的な考え方や目的は同じです。細かな言葉の違いにとらわれすぎないことが重要です。 |
9.2 クライアントとサーバの分離
RESTful APIの1つ目の原則は、クライアント(フロントエンド)とサーバ(バックエンド)を分離することです。両者の通信はHTTPのリクエストとレスポンスのみで行います。
たとえば、ECサイトを例に考えてみます。クライアントとサーバが分離されていない構成では、商品の表示画面とデータベースの処理が一つのシステムに含まれています。この場合、商品画面のデザインを変更しただけで、データベース処理にも予期せぬ影響が出てしまう可能性があります。
一方、クライアントとサーバが分離されている構成では、フロントエンド(商品画面の表示)とバックエンド(商品データの管理)がそれぞれ独立したシステムとして動作します。フロントエンドが商品データを必要とする場合は、バックエンドのAPIに対してHTTPリクエストを送信し、レスポンスとしてJSON形式のデータを受け取ります。
この分離により、以下のメリットが得られます。
- フロントエンドとバックエンドを別々のチームで開発できる
- フロントエンドのデザイン変更がバックエンドに影響しない(その逆も同様)
- 同じAPIをWebアプリ・スマホアプリ・外部サービスなど複数のクライアントから利用できる
9.3 統一されたインタフェース
RESTful APIの2つ目の原則は、HTTPメソッドとパスの組み合わせで操作を統一的に表現することです。
HTTPメソッドとCRUD操作の対応を図に示します。
flowchart LR
GET -->|Read| R["/usersからデータ取得"]
POST -->|Create| C["/usersにデータ作成"]
PUT -->|Update| U["/users/idのデータ更新"]
DELETE -->|Delete| D["/users/idのデータ削除"]
まず、リソースという概念を理解しましょう。リソースとは、APIで操作を行う対象のことです。たとえば、タスク管理アプリであれば「タスク」がリソースになり、ECサイトであれば「商品」や「注文」がリソースになります。RESTful APIでは、リソースはパスで表現し、複数形(tasks、products、ordersなど)で定義するのが一般的です。
このリソースに対して、HTTPメソッドを組み合わせることで「何を」「どうするか」を表現します。タスク管理アプリのtasksリソースを例に見てみましょう。
| HTTPメソッド | パス | 操作 | 説明 |
|---|---|---|---|
GET |
/tasks |
一覧取得 | タスクの一覧を取得する |
GET |
/tasks/{id} |
詳細取得 | 特定のタスクを取得する |
POST |
/tasks |
作成 | 新しいタスクを作成する |
PUT |
/tasks/{id} |
更新 | 特定のタスクを更新する |
DELETE |
/tasks/{id} |
削除 | 特定のタスクを削除する |
この設計の優れている点は、リソースが変わってもルールが同じであることです。たとえば、同じアプリに「ユーザ」リソースを追加する場合も、まったく同じパターンで設計できます。
| HTTPメソッド | パス | 操作 |
|---|---|---|
GET |
/users |
ユーザの一覧を取得する |
POST |
/users |
新しいユーザを作成する |
DELETE |
/users/{id} |
特定のユーザを削除する |
このように統一されたルールに従うことで、APIの利用者はドキュメントを細かく確認しなくても、「GET /productsは商品の一覧を取得するのだろう」「DELETE /orders/5はIDが5の注文を削除するのだろう」と直感的に理解できます。
9.4 ステートレス
RESTful APIの3つ目の原則は、ステートレス(状態を持たない)であることです。これは、サーバがクライアントの状態を記憶しないことを意味します。各リクエストはそれ単体で完結しており、サーバは「このクライアントは前回何をリクエストしたか」といった情報を保持しません。
身近な例で考えてみましょう。レストランの注文を想像してください。
- ステートフル(状態を持つ)な注文方式は、常連客を覚えている店員のようなものです。「いつもの」と言えば前回と同じ注文が通りますが、店員が変わると「いつもの」が通じなくなります。
- ステートレスな注文方式は、毎回メニュー表から注文する方式です。誰が対応しても同じサービスを受けられます。
RESTful APIでは、このステートレスな方式を採用します。たとえば認証が必要なAPIの場合、クライアントは毎回のリクエストに認証情報(トークン)を含めて送信します。
GET /tasks HTTP/1.1
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
サーバは「このクライアントはログイン済みだ」という情報を保持するのではなく、リクエストに含まれるトークンを毎回検証して認証を行います。これにより、以下のメリットが得られます。
- どのサーバがリクエストを処理しても同じ結果が返せるため、負荷分散が容易になる
- サーバがクライアントの状態を管理する必要がないため、サーバの処理が簡略化される
- サーバを複数台に増やしても、サーバ間で状態を共有する必要がない
9.5 キャッシュ可能性
RESTful APIの4つ目の原則は、キャッシュ(データの一時保存)を適切に活用することです。
たとえば、ニュースサイトのトップページを考えてみましょう。記事の一覧データは数分間ほとんど変わりません。にもかかわらず、ユーザがページを開くたびにサーバに問い合わせていたら、サーバへの負荷が不必要に増大してしまいます。そこで、一度取得したデータを一時的に保存しておき、次回アクセス時にはその保存データを再利用する仕組みがキャッシュです。
RESTful APIでは、レスポンスヘッダのCache-Controlによってキャッシュの有効期限を指定します。
Cache-Control: max-age=300
この例では、「このレスポンスを300秒(5分間)キャッシュしてよい」とクライアントに指示しています。5分以内に同じリクエストが発生した場合、クライアントはサーバに問い合わせることなく、保存されたデータを再利用できます。
9.6 階層化された構造
RESTful APIの5つ目の原則は、クライアントとサーバの間に中間層(レイヤ)を配置できる構造にすることです。
たとえば、人気のあるWebサービスでは、大量のリクエストを1台のサーバで処理することは困難です。そこで、クライアントとAPIサーバの間にロードバランサを配置し、リクエストを複数のサーバに振り分けます。
この構成のポイントは、クライアントがロードバランサの存在を意識する必要がないことです。クライアントから見れば、1つのURLにリクエストを送っているだけで、裏側で複数のサーバに振り分けられていることを知る必要はありません。ロードバランサ以外にも、CDN(コンテンツ配信ネットワーク)や認証サーバなどを中間層として配置することができます。
| 📝 直接アクセスの制限 |
|---|
| 中継システム経由でのアクセスに限定したい場合は、セキュリティグループやファイアウォールを用いてAPIへの直接アクセスを制限することが有効です。 |
9.7 RESTful APIのまとめ
ここまで5つの原則を見てきましたが、RESTful APIを一言でまとめると、
- 「HTTPの仕組み(メソッド・パス・ステータスコードなど)を活用して、わかりやすく・拡張しやすいAPIを設計するためのルール です。
たとえば「タスクの一覧を取得したい」ならGET /tasks、「新しいタスクを作成したい」ならPOST /tasksというように、HTTPの仕組みをそのまま活かして直感的にAPIを設計できる点がRESTful APIの大きな特徴です。
RESTful APIの5つの原則をまとめると以下のとおりです。
| 原則 | 概要 |
|---|---|
| クライアントとサーバの分離 | フロントエンドとバックエンドを独立させ、HTTPで通信する |
| 統一されたインタフェース | HTTPメソッドとパスの組み合わせで操作を統一的に表現する |
| ステートレス | サーバはクライアントの状態を保持せず、各リクエストを独立して処理する |
| キャッシュ可能性 | レスポンスをキャッシュして不要な通信を削減する |
| 階層化された構造 | クライアントとサーバの間にロードバランサなどの中間層を配置できる |
10. まとめ
この講座では、Webアプリケーションの基本について学びました。
- Webアプリケーションは、ブラウザを介して利用するアプリケーションで、フロントエンドとバックエンドで構成される
- HTTPは、クライアントとサーバ間でデータをやり取りするための通信プロトコルである
- HTTPリクエストはメソッド、パス、ヘッダ、ボディで構成される
- HTTPメソッドには
GET(取得)、POST(作成)、PUT(更新)、DELETE(削除)がある - ステータスコードにより、処理結果をクライアントに伝える(
2xx:成功、4xx:クライアントエラー、5xx:サーバエラー) - APIは異なるシステム間でデータをやり取りする仕組みであり、JSON形式が広く利用されている
- RESTful APIはクライアントとサーバの分離、統一されたインタフェース、ステートレスなどの設計原則に基づく
- 次の講座FastAPI入門では、PythonのWebフレームワークであるFastAPIの基本について学びます