PHPでREST APIを設計する際には、エンドポイントの構成やデータ形式、認証方法など、さまざまな要素を適切に設計することが重要です。APIはWebアプリケーションとクライアント間の橋渡し役を果たし、データの取得や操作を効率的に行うためのインターフェースとして機能します。特に、スケーラビリティやセキュリティを考慮した設計は、サービスの品質向上とメンテナンス性の向上に寄与します。本記事では、PHPでのREST API設計における基本的な概念から具体的なベストプラクティスまでを詳しく解説し、より効率的で堅牢なAPIを作成するための指針を提供します。
REST APIの基本概念とその重要性
REST(Representational State Transfer)は、Webサービスを設計するためのアーキテクチャスタイルで、HTTPプロトコルを活用してクライアントとサーバー間でデータをやり取りします。REST APIは、リソースベースのURL設計とHTTPメソッド(GET、POST、PUT、DELETEなど)を組み合わせて、リソースの操作を効率的に行うことを可能にします。
REST APIの基本原則
RESTは以下の基本原則に基づいて設計されています。
- ステートレス性:各リクエストは独立しており、サーバーはクライアントの状態を保持しません。
- リソース指向:URLはリソース(データ)を表し、HTTPメソッドによって操作が決まります。
- 統一インターフェース:標準的な方法でリソースを操作するため、クライアントとサーバー間の統一性が保たれます。
REST APIがWebサービスで重要な理由
REST APIは、以下の点でWebサービス開発において非常に重要です。
- 柔軟性:リソース操作を標準化することで、複数のクライアント(Webブラウザ、モバイルアプリなど)からのアクセスが可能になります。
- スケーラビリティ:ステートレス性により、サーバー負荷の分散が容易であり、大規模なシステムでも対応可能です。
- 開発の容易さ:標準的なHTTPプロトコルを使用するため、既存のツールやライブラリを活用できます。
REST APIの基本概念を理解することは、効率的で堅牢なWebサービスを設計するための第一歩です。
エンドポイント設計の基本原則
エンドポイント設計は、REST APIのユーザビリティと保守性に大きく影響します。適切なエンドポイントの命名規則や構成を取り入れることで、APIの使いやすさと一貫性を向上させることができます。
エンドポイントの命名規則
エンドポイントはリソースを表す名詞を使用し、操作の対象を明確にします。例えば、ユーザーを表す場合は「/users」、記事を表す場合は「/articles」といった形で命名します。一般的なルールは以下の通りです。
- 複数形を使用する:リソースはコレクションとして扱うため、「/user」ではなく「/users」のように複数形にします。
- 小文字とハイフンを使用する:URLは小文字を用い、「/user-profile」などの形で単語の区切りにはハイフンを使います。
HTTPメソッドとの組み合わせ
HTTPメソッドを活用することで、同じリソースに対して異なる操作を指定できます。以下は一般的なメソッドの使用例です。
- GET:リソースの取得(例:「GET /users」)
- POST:新しいリソースの作成(例:「POST /users」)
- PUT:リソースの完全更新(例:「PUT /users/1」)
- PATCH:リソースの部分更新(例:「PATCH /users/1」)
- DELETE:リソースの削除(例:「DELETE /users/1」)
リソースの階層構造と関係性の表現
リソースの階層をURLで表現することで、リソース間の関係性を示すことができます。例えば、特定ユーザーのコメントを取得する場合、「/users/1/comments」のように親子関係を反映させます。
これらの基本原則に従うことで、APIの使いやすさとメンテナンス性を高めることができます。
リクエストとレスポンスの形式設計
REST APIの設計において、リクエストとレスポンスの形式を適切に設計することは、データの一貫性と操作性を確保する上で重要です。標準的なデータ形式やステータスコードを使用することで、クライアントとサーバー間のコミュニケーションを円滑に行えます。
JSONを中心としたフォーマット選定
REST APIでは、データ形式としてJSON(JavaScript Object Notation)が一般的に使用されます。JSONは軽量で読みやすく、さまざまなプログラミング言語で容易にパースできるため、API開発に適しています。リクエストおよびレスポンスのContent-Typeヘッダーには「application/json」を指定し、データ形式の一貫性を保つことが推奨されます。
ステータスコードの使用方法
HTTPステータスコードを適切に使用することで、リクエストの結果をクライアントに明示できます。一般的なステータスコードの例を以下に示します。
- 200 OK:リクエストが成功し、レスポンスにデータを含む場合に使用します。
- 201 Created:新しいリソースが作成された場合に使用します。
- 400 Bad Request:リクエストが無効な場合に返されます(例:不正な入力データ)。
- 401 Unauthorized:認証が必要で、未認証のユーザーがアクセスした場合に使用します。
- 404 Not Found:リクエストされたリソースが見つからない場合に返されます。
- 500 Internal Server Error:サーバー内部でエラーが発生した場合に使用します。
レスポンスの構造設計
レスポンスのデータ構造は、データの内容とエラーメッセージの標準化を考慮します。例えば、成功時には以下のような形式を使用します。
{
"status": "success",
"data": {
"id": 1,
"name": "John Doe",
"email": "john.doe@example.com"
}
}
エラー時には、以下のような形式でエラーメッセージを返します。
{
"status": "error",
"message": "Invalid request parameters",
"code": 400
}
リクエストとレスポンスの形式を統一することで、APIの信頼性と開発効率が向上します。
認証と認可の実装方法
REST APIでは、データの保護とアクセス制御のために認証(authentication)と認可(authorization)が重要です。適切な認証と認可の仕組みを導入することで、セキュアで信頼性の高いAPIを提供できます。
トークンベースの認証
トークンベースの認証は、APIクライアントの認証情報をトークンとして扱う方式です。一般的にはJWT(JSON Web Token)を使用します。JWTは、クライアントがログイン時に認証サーバーから発行され、その後のリクエスト時にAuthorizationヘッダーにトークンを含めることで認証を行います。
- ログインフロー:クライアントはログインエンドポイントにユーザー名とパスワードを送信し、サーバーが検証後にJWTを発行します。
- リクエスト時の使用:クライアントはリクエストのAuthorizationヘッダーに「Bearer トークン」の形式でJWTを含めてサーバーに送信します。
- サーバー側のトークン検証:サーバーは受け取ったJWTの有効性を確認し、必要に応じてクレーム(ユーザー情報など)をデコードして利用します。
OAuthによる認可
OAuthは、ユーザーの代わりにリソースへのアクセスを許可するための標準的なプロトコルです。APIにアクセスする第三者アプリケーションに対して、アクセス権を安全に付与することができます。
- OAuth 2.0のフロー:クライアントは、リソース所有者(ユーザー)の同意を得た後、認可サーバーからアクセストークンを取得します。このアクセストークンを使用して、リソースサーバーに対するリクエストを行います。
- アクセストークンの有効期限:アクセストークンには有効期限が設定されており、定期的に更新が必要です。リフレッシュトークンを使用することで、アクセストークンの再発行が可能です。
APIキーによるシンプルな認証
APIキーを使用する認証は、シンプルな認証手法として用いられます。クライアントはリクエストのヘッダーやクエリパラメータにAPIキーを含めてサーバーにアクセスしますが、セキュリティ面では他の方式よりも弱いため、他の認証方法と併用することが推奨されます。
ロールベースのアクセス制御(RBAC)
認可の実装では、ユーザーのロール(役割)に応じたアクセス制御を行うロールベースのアクセス制御(RBAC)が有効です。各ユーザーに対して異なる権限を設定することで、リソースへの適切なアクセス管理を実現します。
適切な認証と認可を導入することで、REST APIのセキュリティを確保し、不正アクセスを防止できます。
エラーハンドリングのベストプラクティス
REST APIでは、エラー発生時に適切なレスポンスをクライアントに返すことが重要です。エラーハンドリングを標準化し、詳細なエラーメッセージとステータスコードを適切に使用することで、クライアントが問題を特定しやすくなります。
標準化されたエラーレスポンス
エラーレスポンスの形式を統一することで、API利用者にとって予測可能な振る舞いを提供できます。一般的には、以下のような構造でエラーレスポンスを返します。
{
"status": "error",
"message": "Resource not found",
"code": 404,
"details": {
"field": "id",
"issue": "Invalid format"
}
}
この形式により、エラーの種類や詳細な情報を一目で理解できるようにします。status
フィールドにはエラーであることを示す文字列を、message
にはユーザー向けのエラーメッセージを記載します。code
にはHTTPステータスコードを、details
にはエラーの詳細情報を含めることで、デバッグが容易になります。
HTTPステータスコードの適切な使用
エラー状況に応じたHTTPステータスコードを使用することで、クライアントに対して適切なフィードバックを提供します。以下は、一般的なエラー状況と対応するステータスコードの例です。
- 400 Bad Request:リクエストが不正である場合(例:バリデーションエラー)。
- 401 Unauthorized:認証が必要であるが、未認証のユーザーがリクエストを行った場合。
- 403 Forbidden:認証は成功したが、権限がない場合。
- 404 Not Found:リクエストされたリソースが存在しない場合。
- 409 Conflict:リクエストがリソースの現在の状態と競合する場合(例:重複したデータの挿入)。
- 500 Internal Server Error:サーバー内部で予期しないエラーが発生した場合。
エラーの分類とロギング
エラーを分類し、それぞれに対する適切な対処を行います。たとえば、クライアントエラー(400番台)とサーバーエラー(500番台)を区別し、異なるログ出力や通知方法を設定します。
- クライアントエラー:ユーザーによる操作ミスや不正な入力データに起因するエラーであり、ユーザーに対するエラーメッセージを適切に表示する必要があります。
- サーバーエラー:内部処理の問題によるエラーであり、詳細なエラーログを記録し、管理者に通知する仕組みが必要です。
カスタムエラーメッセージの実装
デフォルトのエラーメッセージに加えて、特定の状況に応じたカスタムメッセージを提供することで、クライアントが問題の原因を特定しやすくなります。例えば、バリデーションエラーの詳細を返す場合、「email
フィールドが無効です」のような具体的な情報を含めます。
エラーハンドリングを適切に実装することで、APIの信頼性が向上し、クライアント側でのトラブルシューティングが容易になります。
データのバリデーションとサニタイズ
REST APIでは、リクエストデータの信頼性を確保するために、バリデーション(入力検証)とサニタイズ(データの安全化)が必要です。これにより、不正なデータの保存を防ぎ、セキュリティを強化することができます。
データバリデーションの重要性
バリデーションとは、リクエストされたデータが特定の基準を満たしているかを確認するプロセスです。これにより、サーバーに渡されるデータが適切であることを保証できます。以下のポイントに基づいてバリデーションを行います。
- 型の検証:入力データが期待される型(文字列、数値、ブール値など)であるか確認します。
- 必須フィールドのチェック:必須のデータが欠落していないかを検証します。
- 値の範囲と長さの制限:数値の範囲や文字列の長さに制限を設けます。
- 正規表現によるパターンマッチング:メールアドレスや電話番号など、特定の形式を持つデータを検証します。
サニタイズの方法
サニタイズとは、入力データを安全な形式に変換するプロセスです。特に、ユーザーからの入力を処理する際に、サニタイズを行わないと、SQLインジェクションやクロスサイトスクリプティング(XSS)などの脆弱性が発生する可能性があります。
- HTMLエスケープ:HTMLタグがそのまま出力されないように、特殊文字をエスケープします。
- SQLエスケープ:データベースに渡す際に、SQLクエリを操作されないようエスケープ処理を行います。
- JavaScriptエスケープ:JavaScriptで使用する場合、特殊文字を適切にエスケープして、コード実行を防ぎます。
PHPでのバリデーションとサニタイズの実装例
以下の例では、PHPのfilter_var()
関数を用いて、入力データのバリデーションとサニタイズを行っています。
// バリデーション:メールアドレスが有効かどうかを確認
$email = $_POST['email'];
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
echo "無効なメールアドレスです。";
}
// サニタイズ:HTMLタグを削除し、SQLインジェクション対策
$name = htmlspecialchars($_POST['name'], ENT_QUOTES, 'UTF-8');
このように、バリデーションでデータの正確性を確保し、サニタイズでデータの安全性を確保することが推奨されます。
エラー処理とフィードバックの提供
バリデーションエラーが発生した場合、適切なエラーメッセージをクライアントに返すことが重要です。詳細なエラーメッセージを提供することで、クライアントは入力データを修正しやすくなります。
{
"status": "error",
"message": "無効な入力があります",
"errors": {
"email": "有効なメールアドレスを入力してください",
"name": "名前は必須です"
}
}
このようなエラーレスポンスを返すことで、ユーザーの入力改善を促すことができます。
データのバリデーションとサニタイズは、APIの安全性と信頼性を高めるために不可欠なプロセスです。
ページネーションとフィルタリングの設計
大量のデータを効率的に処理するために、REST APIではページネーションとフィルタリングを設計することが重要です。これにより、クライアントが必要なデータを迅速に取得できるようになり、サーバーへの負荷も軽減されます。
ページネーションの基本概念
ページネーションは、データを小さな単位(ページ)に分割して提供する手法です。REST APIでの一般的なページネーションの方法には、以下の2つがよく使用されます。
- オフセットとリミット方式:
offset
とlimit
パラメータを使用して、データの開始位置と取得件数を指定します。例:GET /users?offset=0&limit=10
- ページ番号とページサイズ方式:
page
とper_page
パラメータを使用して、特定のページを取得します。例:GET /users?page=1&per_page=10
これらの方式を使うことで、大量のデータを適切に分割し、必要なデータのみを取得することができます。
ページネーションレスポンスの設計
ページネーションを実装する際、レスポンスにページ情報を含めることで、クライアントが次のデータを取得しやすくなります。以下のような形式でページネーション情報をレスポンスに含めます。
{
"status": "success",
"data": [
{
"id": 1,
"name": "John Doe"
},
{
"id": 2,
"name": "Jane Smith"
}
],
"pagination": {
"current_page": 1,
"per_page": 10,
"total_pages": 5,
"total_items": 50
}
}
このように、現在のページ情報や全体のアイテム数をレスポンスに含めることで、クライアント側でのページネーションの制御が容易になります。
フィルタリングの設計
フィルタリングは、リクエストに基づいて特定の条件に一致するデータのみを取得する手法です。クエリパラメータを使用してフィルタ条件を指定します。例:
- 特定のフィールドでのフィルタリング:
GET /users?role=admin
で、role
がadmin
のユーザーのみを取得。 - 範囲によるフィルタリング:
GET /products?price_min=100&price_max=500
で、価格が100から500の範囲にある商品を取得。 - 複数のフィルタ条件:
GET /orders?status=shipped&date_min=2024-01-01
で、出荷済みかつ指定された日付以降の注文を取得。
ページネーションとフィルタリングの組み合わせ
ページネーションとフィルタリングは、同時に適用することが一般的です。たとえば、GET /users?role=admin&page=2&per_page=20
のように、特定の条件でフィルタリングした結果に対してページネーションを適用します。
キャッシュの利用によるパフォーマンス向上
大規模なデータセットでのページネーションやフィルタリングを行う場合、キャッシュを活用することでパフォーマンスを向上させることが可能です。特に、頻繁にアクセスされるリソースに対しては、キャッシュを活用してサーバーの負荷を軽減することが推奨されます。
ページネーションとフィルタリングを適切に設計することで、クライアントに対して効率的なデータ提供が可能になり、APIのパフォーマンスも向上します。
バージョン管理と互換性の保持
REST APIを開発する際、APIのバージョン管理は重要な課題です。バージョン管理を適切に行うことで、新しい機能の追加や既存機能の変更を行っても、既存のクライアントに対して後方互換性を保つことができます。
APIバージョン管理の方法
APIのバージョン管理にはいくつかのアプローチがあります。一般的には、URLにバージョンを含める方法が最も広く採用されています。
- URLパスにバージョンを含める:
/v1/users
や/v2/users
のように、APIのバージョンをURLパスに追加します。この方法はシンプルでわかりやすく、クライアント側で異なるバージョンのAPIを明確に区別できます。 - クエリパラメータで指定する:
/users?version=1
のように、クエリパラメータでバージョンを指定する方法です。明示的ではないため、あまり一般的ではありません。 - HTTPヘッダーでバージョンを指定する:リクエストのヘッダーに
Accept
ヘッダーを使用して、application/vnd.example.v1+json
のようにバージョンを指定する方法です。この方法は柔軟性が高く、URLの構造を変更せずにバージョン管理ができます。
後方互換性を維持するためのベストプラクティス
APIの進化に伴い、新しい機能や変更が必要になりますが、既存のクライアントに影響を与えないようにすることが重要です。以下は、後方互換性を保つための一般的なベストプラクティスです。
- 非推奨機能の段階的廃止:既存のエンドポイントや機能を突然削除するのではなく、「非推奨」(deprecated)として通知し、一定期間はサポートを継続します。ドキュメントに非推奨であることを明記し、利用者に移行を促します。
- 新機能の追加は既存のエンドポイントに影響しないようにする:新しいフィールドの追加や機能の拡張は、既存のエンドポイントやデータ構造を壊さない形で行います。たとえば、新しいオプションを追加する場合、デフォルトで旧動作を維持します。
- バージョン間の明確な違いをドキュメント化する:異なるバージョン間での変更点や非互換性については、ドキュメントで詳細に説明します。クライアントが新しいバージョンに適応するための情報を提供します。
APIの互換性テスト
APIのバージョンが増えると、すべてのバージョンに対して互換性テストを行う必要があります。テスト自動化ツールやスクリプトを用いて、異なるバージョンのエンドポイントに対するテストを行い、変更が既存の機能に影響を与えないことを確認します。
バージョン管理とマイクロサービスの関係
マイクロサービスアーキテクチャでは、各サービスが独立してバージョン管理を行うことが可能です。これにより、個別のサービスを柔軟にアップデートでき、システム全体の進化を効率的に行うことができます。ただし、依存関係があるサービス間でのバージョン互換性にも注意を払う必要があります。
バージョン管理を適切に行うことで、APIの進化に伴う混乱を最小限に抑え、既存のクライアントとの互換性を維持できます。
キャッシュの活用によるパフォーマンス向上
REST APIのパフォーマンスを向上させるために、キャッシュの活用は非常に効果的です。キャッシュを適切に実装することで、サーバーへの負荷を減らし、クライアントへのレスポンス時間を短縮できます。
キャッシュの基本概念
キャッシュとは、頻繁にアクセスされるデータを一時的に保存することで、再リクエスト時にデータの取得を高速化する仕組みです。REST APIにおけるキャッシュは、HTTPのキャッシュ機構を利用して実現されることが多いです。以下のHTTPヘッダーを活用することで、キャッシュを管理します。
- Cache-Control:キャッシュの有効期間やキャッシュの可否を指定します。例:
Cache-Control: max-age=3600
(1時間キャッシュする)。 - ETag:リソースのバージョンを識別するためのタグで、リソースが変更されたかどうかを判別します。例:
ETag: "34a64df551429fcc55e"
. - Last-Modified:リソースが最後に変更された日時を示し、それ以降に変更がなければキャッシュを再利用できます。
キャッシュ戦略の設計
REST APIでは、キャッシュ戦略を以下のように設定することで、パフォーマンスを最適化します。
- パブリックキャッシュとプライベートキャッシュ:
public
キャッシュは、すべてのクライアントが利用できるキャッシュで、private
キャッシュは特定のクライアントに限定されます。ユーザーごとに異なるデータをキャッシュする場合はprivate
を使用します。 - キャッシュの有効期間設定:
max-age
やs-maxage
を使用してキャッシュの有効期間を設定します。短期間で頻繁に更新されるデータには短い期間を、あまり変更されないデータには長い期間を設定します。 - 条件付きリクエストの活用:
If-None-Match
(ETag)やIf-Modified-Since
(Last-Modified)を使用して、サーバーに変更がない場合は304ステータスコードを返し、データの再送信を省略します。
キャッシュの制御方法
キャッシュ制御は、適切なヘッダーの設定によって管理します。
- Cache-Controlの設定例:
Cache-Control: no-store
(キャッシュしない)、Cache-Control: no-cache
(キャッシュはされるが再検証が必要)、Cache-Control: max-age=86400
(1日間キャッシュする)。 - ETagの生成と管理:リソースの変更時に新しいETagを生成し、クライアントが持つETagと一致しない場合にデータを返します。これにより、変更の有無を効率的に判断できます。
クライアント側のキャッシュ活用
クライアント側でも、キャッシュを活用することでパフォーマンスを向上できます。例えば、ブラウザやモバイルアプリは、キャッシュされたデータを使用する前にサーバーに対して条件付きリクエストを送信し、リソースが変更されていないか確認します。これにより、不要なデータ転送を防ぐことが可能です。
キャッシュとセキュリティの考慮
キャッシュを利用する際は、セキュリティ面の考慮も必要です。特に、認証が必要なリソースについては、private
キャッシュを使用してキャッシュの範囲を制限し、機密情報が誤ってキャッシュされないようにします。また、機密情報を含むレスポンスには、Cache-Control: no-store
を設定することで、キャッシュを防ぎます。
キャッシュを適切に活用することで、REST APIのパフォーマンスを大幅に向上させるとともに、ユーザー体験の向上にもつながります。
テストとデバッグの方法
REST APIの開発では、テストとデバッグが不可欠です。APIが正しく機能するかを確認することで、品質を保証し、不具合を早期に発見できます。テスト自動化やデバッグツールを用いることで、効率的に開発を進めることができます。
APIテストの種類
APIテストにはさまざまな種類がありますが、以下の3つが特に重要です。
- ユニットテスト:個々のエンドポイントや機能をテストし、期待される出力が得られるかを検証します。PHPでは、PHPUnitを使用してユニットテストを実行することが一般的です。
- 統合テスト:複数のAPIエンドポイントが正しく連携して動作するかを確認します。API間の依存関係がある場合に特に重要です。
- エンドツーエンド(E2E)テスト:APIをクライアントから利用するシナリオを再現し、ユーザーの操作と同じフローでテストを行います。PostmanやCypressなどのツールを使用して、シナリオベースのテストを自動化できます。
テスト自動化の実装
テストを自動化することで、APIの変更が他の機能に影響を与えていないかを継続的に確認できます。PHPでの自動化テストの例として、PHPUnitを使用してユニットテストを行う方法を示します。
use PHPUnit\Framework\TestCase;
class UserApiTest extends TestCase
{
public function testGetUser()
{
$response = $this->call('GET', '/api/v1/users/1');
$this->assertEquals(200, $response->status());
$this->assertJson($response->getContent());
}
}
この例では、特定のユーザーを取得するエンドポイントのテストを実施し、HTTPステータスコードやレスポンス形式が正しいかを検証しています。
デバッグツールの活用
REST APIの開発中に発生する問題を効率的に特定するためには、デバッグツールを使用することが有効です。
- Postman:APIリクエストを手動でテストできるツールで、エンドポイントのテストやレスポンスの確認に便利です。
- Xdebug:PHPのデバッグツールで、コードのステップ実行や変数の状態確認を行いながら不具合を特定します。
- Logファイルの活用:エラーログやアクセスログを活用して、APIの問題の原因を追跡します。エラーハンドリングで適切なログを出力することが推奨されます。
テスト駆動開発(TDD)の導入
テスト駆動開発(TDD)は、テストを先に書き、それからコードを実装する手法です。これにより、開発の初期段階から高い品質を保証し、後の変更による不具合を防ぐことができます。
- 失敗するテストを書く:最初に、失敗するテストケースを作成します。
- テストをパスするコードを書く:そのテストケースをクリアするために、必要な最低限のコードを書きます。
- リファクタリングする:コードの品質を向上させつつ、すべてのテストがパスするようにします。
エラーハンドリングのテストと改善
APIのエラーハンドリングが正しく機能することを確認するテストも重要です。例えば、不正なリクエストに対して適切なエラーメッセージとHTTPステータスコードが返されるかをテストします。以下はエラーハンドリングのテスト例です。
public function testInvalidUserId()
{
$response = $this->call('GET', '/api/v1/users/9999');
$this->assertEquals(404, $response->status());
$this->assertStringContainsString('User not found', $response->getContent());
}
このテストにより、存在しないユーザーIDに対して404エラーが返されることを検証します。
テストとデバッグを適切に行うことで、APIの品質を高め、開発速度を維持しつつ信頼性の高いシステムを構築できます。
まとめ
本記事では、PHPでのREST API設計における重要なポイントとベストプラクティスについて解説しました。API設計の基本概念から、エンドポイントの設計、リクエスト・レスポンス形式の管理、認証・認可の実装、エラーハンドリング、データバリデーション、ページネーション、バージョン管理、キャッシュ活用、そしてテストとデバッグの手法まで、幅広いトピックをカバーしました。
これらの知識を活用することで、スケーラブルでメンテナンスしやすいAPIを構築し、ユーザー体験の向上とシステムの安定性を確保することが可能です。継続的なテストと改善を行い、より良いAPIを目指しましょう。
コメント