チュートリアル:RESTful API の構築#
このチュートリアルでは、RESTful JSON API を構築します。この API は、OpenAPI ドキュメントを自動生成し、リクエストとレスポンスのデータを検証します。
このチュートリアルは、Quart で API を構築するための入門として役立つことを目的としています。最後まで飛ばしたい場合は、コードはGithubにあります。
1:プロジェクトの作成#
API サーバー用のプロジェクトを作成する必要があります。私はこれを行うためにPoetryを使用することをお勧めします。Poetry は pip(またはBrew)を使用してインストールできます。
pip install poetry
Poetry を使用して、新しい API プロジェクトを作成できます。
poetry new --src api
プロジェクトはこれで *api* ディレクトリで開発でき、以降のコマンドはすべて *api* ディレクトリ内で実行する必要があります。
2:依存関係の追加#
最初に、API サーバーを構築するために Quart だけが必要です。これは、次のコマンドを実行することで、プロジェクトの依存関係としてインストールできます。
poetry add quart
Poetry は、この依存関係が存在し、パスが正しいことを、次のコマンドを実行することで確認します。
poetry install
3:アプリの作成#
Web サーバーとなる Quart アプリが必要です。これは、 *src/api/__init__.py* に以下を追加することで作成できます。
from quart import Quart
app = Quart(__name__)
def run() -> None:
app.run()
アプリを簡単に実行するために、 *pyproject.toml* に以下を追加して、Poetry スクリプトから run メソッドを呼び出すことができます。
[tool.poetry.scripts]
start = "api:run"
これにより、次のコマンドでアプリを起動できます。
poetry run start
4:シンプルな JSON API の追加#
まず、送信された JSON を読み取り、レスポンスでそれをエコーバックするルートを追加できます。そのためには、 *src/api/__init__.py* に以下を追加します。
from quart import request
@app.post("/echo")
async def echo():
data = await request.get_json()
return {"input": data, "extra": True}
これは curl を使用してテストできます。
curl --json '{"hello": "world"}' https://:5000/echo
結果は次のようになります。
{"extra":true,"input":{"hello":"world"}}
明確にするために、ルートハンドラーから返された辞書は、正しい Content-Type ヘッダー付きで JSON としてレスポンスに返されます。トップレベルの配列を JSON レスポンスとして返す場合は、jsonify 関数を次のように使用できます。
from quart import jsonify
@app.get("/example")
async def example():
return jsonify(["a", "b"])
5:スキーマの追加#
Quart-Schema 拡張機能を使用すると、リクエストとレスポンスのデータを検証するためのスキーマを定義できます。さらに、Quart-Schema はこれらのスキーマを使用して OpenAPI (Swagger) ドキュメントを自動生成します。まず、quart-schema をインストールする必要があります。
poetry add quart-schema
次に、Todo オブジェクトのスキーマを *src/api/__init__.py* に追加できます。
from dataclasses import dataclass
from datetime import datetime
from quart import Quart
from quart_schema import QuartSchema, validate_request, validate_response
app = Quart(__name__)
QuartSchema(app)
@dataclass
class TodoIn:
task: str
due: datetime | None
@dataclass
class Todo(TodoIn):
id: int
@app.post("/todos/")
@validate_request(TodoIn)
@validate_response(Todo)
async def create_todo(data: TodoIn) -> Todo:
return Todo(id=1, task=data.task, due=data.due)
OpenAPI スキーマは https://:5000/openapi.json で、ドキュメント自体は https://:5000/docs で利用できます。
6:テスト#
アプリをテストするには、echo ルートが送信された JSON データを返し、create_todo ルートが todo を作成することを確認する必要があります。これは、 *tests/test_api.py* に以下を追加することで行います。
from api import app, TodoIn
async def test_echo() -> None:
test_client = app.test_client()
response = await test_client.post("/echo", json={"a": "b"})
data = await response.get_json()
assert data == {"extra":True,"input":{"a":"b"}}
async def test_create_todo() -> None:
test_client = app.test_client()
response = await test_client.post("/todos/", json=TodoIn(task="Abc", due=None))
data = await response.get_json()
assert data == {"id": 1, "task": "Abc", "due": None}
テストは非同期関数であるため、次のコマンドを実行して pytest-asyncio をインストールする必要があります。
poetry add --dev pytest-asyncio
インストール後、 *pyproject.toml* に以下を追加して構成する必要があります。
[tool.pytest.ini_options]
asyncio_mode = "auto"
最後に、次のコマンドでテストを実行できます。
poetry run pytest tests/
Quart のサンプルフォルダでこれを実行している場合、pytest が Quart の pytest 構成を使用しないように、-c pyproject.toml オプションを追加する必要があります。
7:まとめ#
自動生成された OpenAPI ドキュメントと検証機能を備えた RESTful API サーバーを構築しました。このコードを使用して、あらゆる API を構築できます。