チュートリアル: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* に以下を追加することで作成できます。

src/api/__init__.py#
from quart import Quart

app = Quart(__name__)

def run() -> None:
    app.run()

アプリを簡単に実行するために、 *pyproject.toml* に以下を追加して、Poetry スクリプトから run メソッドを呼び出すことができます。

pyproject.toml#
[tool.poetry.scripts]
start = "api:run"

これにより、次のコマンドでアプリを起動できます。

poetry run start

4:シンプルな JSON API の追加#

まず、送信された JSON を読み取り、レスポンスでそれをエコーバックするルートを追加できます。そのためには、 *src/api/__init__.py* に以下を追加します。

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* に追加できます。

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* に以下を追加することで行います。

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 を構築できます。