Skip to the content.

エンドポイントの作成

ここでは、ユーザーデータを作成、取得、更新、削除を行うエンドポイントを作成してきます。初めに FastAPI のパラメータ取得方法を解説しますが、公式サイトで既に知っている方は、スキップしてください。

目次

パラメータの取得(スキップ可)

FastAPI におけるパスパラメータ、クエリパラメータ、リクエストボディの取得の仕方について説明します。公式サイトのチュートリアルでも分かりやすく説明されているので、公式サイトも参照してください。ここでは、簡単に説明します。

パスパラメータ

パスパラメータは、format 文字列と同様のシンタックスで取得できます。app/api/endpoints/root.pyを以下のように編集してみましょう。

app/endpoints/root.py

from fastapi import APIRouter

router = APIRouter()


@router.get("/")
def root():
    return {"API": "Active"}

@router.get("/items/{item_id}")
def read_item(item_id):
    return {"item_id": item_id}

サーバーを起動(uvicorn app.main:app --reload --port 8000実行)後、http://127.0.0.1:8000/items/fooにアクセスすると以下のようなレスポンスが表示されるはずです。

{ "item_id": "foo" }

また、以下のようにすることで、パスパラメータの型を宣言することができ、その型に自動的に変換されます。

@router.get("/items/{item_id}")
def read_item(item_id: int):
    return {"item_id": item_id}

サーバーを起動後、http://127.0.0.1:8000/items/3にアクセスすると以下のようなレスポンスが得られます。

{ "item_id": 3 }

型を宣言すると、バリデーションも行うので、http://127.0.0.1:8000/items/fooにアクセスすると、以下のような HTTP エラーが表示されます。

{
  "detail": [
    {
      "type": "int_parsing",
      "loc": [
        "path",
        "item_id"
      ],
      "msg": "Input should be a valid integer, unable to parse string as an integer",
      "input": "foo"
    }
  ]
}

クエリパラメータ

パスパラメータではないものをパスオペレーション関数の引数とすると、自動的にクエリパラメータとして解釈されます。 app/endpoints/root.pyの末尾に以下を追加してみましょう。

@router.get("/items/")
def read_items(skip: int = 0, limit: int = 10):
    fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
    return fake_items_db[skip : skip + limit]

次の URL にだと

http://127.0.0.1:8000/items/?skip=1&limit=20

クエリパラメータは、skip1limit20と解釈されます。また、今回は型も宣言されているので、バリデーションも行われます。ちなみにリクエストに対するレスポンスは、以下のようになります。

[{ "item_name": "Bar" }, { "item_name": "Baz" }]

リクエストボディ

クライアント (ブラウザなど) から API にデータを送信する必要があるとき、データを リクエストボディ (request body) として送ります。

FastAPI では、リクエストボディは pydantic を利用して型を定義します。この型を定義は、スキーマと呼びapp/schemaディレクトリにファイルを作っていきます。以下のファイルを作成しましょう。

app/schemas/root.py

from pydantic import BaseModel


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None

また、app/api/endpoints/root.pyで定義したスキーマをインポートし、パスオペレーション関数を追加しましょう。

app/api/endpoints/root.py

from app.schemas.root import Item

@router.post("/items/")
def create_item(item: Item):
    return item

さて、このエンドポイントを試すためには、リクエストボディを記述する必要があります。その場合は Swagger UI を使いましょう。サーバーを起動後、http://127.0.0.1:8000/docsにアクセスしましょう。先ほど作成したエンドポイントPOST /items/を開き、Try it outボタンを押しましょう。以下のような画面になるので、リクエストボディを自由に編集することができます。自分の好きなパラメータで試してみましょう。

SwaggerUI Request body

作成するエンドポイント

ここからは、ユーザーデータの追加、取得、更新、削除を行うエンドポイントを作成します。 ユーザーデータは、本来 DB に保存しますが、それは後で行います。

それでは、まずパスオペレーション関数を定義していきましょう。今回作成するエンドポイントは、ユーザー関連のエンドポイントなので、共通のパス/usersをつけています。この場合、ルーターをまとめる際にprefixで定義します。パスオペレーション関数では、/usersを除いた部分のみ定義します。以下のファイルを作成してください。

app/api/endpoints/users.py

from fastapi import APIRouter

router = APIRouter()


@router.post("")
def create_user():
    pass


@router.get("")
def read_user():
    pass


@router.put("/{signin_id}")
def update_user():
    pass


@router.delete("/{signin_id}")
def delete_user():
    pass

このルーターをprefix = "/users"で追加します。app/api/api.pyを以下のように編集してください。

app/api/api.py

from fastapi import APIRouter

from app.api.endpoints import root, users

api_router = APIRouter()
api_router.include_router(root.router, tags=["test"])
api_router.include_router(users.router, tags=["users"], prefix="/users")

これで、一度サーバーを起動して、Swagger UI を見てみましょう。

SwaggerUI Request body

新しく定義されたエンドポイントが追加されているはずです。

スキーマの定義

パスオペレーション関数の具体的な定義を書く前に、リクエストボディやレスポンスボディのスキーマを定義していきます。

リクエストボディでも説明しましたが、FastAPI では、Pydantic を利用して API のリクエストとレスポンスの型のバリデーションを行います。この型定義のことをスキーマと呼んでいます。

さて、リクエストボディが必要になるエンドポイントは、以下2つです。

スキーマをそれぞれUserCreateUserUpdateとして定義します。スキーマの定義は、app/schemasディレクトリで行います。以下のファイルを追加してください。

app/schemas/user.py

from typing import Optional

from pydantic import BaseModel


class UserCreate(BaseModel):
    signin_id: str
    password: str
    name: Optional[str] = ""
    role: Optional[str] = "User"


class UserUpdate(BaseModel):
    signin_id: str | None = None
    password: str | None = None
    name: str | None = None

また、レスポンスボディとして返すスキーマも定義します。password をレスポンスとして返すわけにはいかないので、password 以外の閲覧してもいいようなデータをレスポンスとして返しましょう。app/schemas/user.pyに以下のスキーマを追加してください。

app/schemas/user.py

class UserResponse(BaseModel):
    signin_id: str
    name: str
    role: str

ここで、定義したスキーマをパスオペレーション関数で使っていくのですが、パスオペレーション関数などで、import した際に、このクラスがスキーマであることを認識したいです。今後、DB などの連携を行うと DB のクラスなども import するため、スキーマなのか DB のクラスなのか混乱させないためです。

そのため、他のファイルでは、schemas.UserCreateという参照の仕方をしたいです。これを行うには、app/schemas/__init__.pyを以下のように編集してください。

app/schemas/__init__.py

from .user import UserCreate, UserUpdate, UserResponse

パスオペレーション関数の定義

ここから、パスオペレーション関数の定義をしていきましょう。ユーザーデータは本来、DB に格納しますが、ここでは、疑似的な DB としてリストに保持することとします。以下のようにapp/api/endpoints/users.pyに疑似的な DB を書きます。

app/api/endpoints/users.py

#  疑似的なDB
from pydantic import BaseModel


class User(BaseModel):
    signin_id: str
    password: str
    name: str
    role: str


fake_user_db = [User(signin_id="tarou", password="tarou", name="太郎", role="User")]

そして、app/api/endpoints/users.pyにて以下を追加し、スキーマを import しておきましょう。

app/api/endpoints/users.py

from app import schemas

それでは、エンドポイントを順に書き換えて行きましょう。

これで完了です。レスポンスのスキーマは、@router.get(...)などにキーワード引数response_modelとして渡しています。ユーザーデータの取得を例として挙げると、以下の通りです。

@router.get("", response_model=List[schemas.UserResponse])
def read_user(skip: int = 0, limit: int = 100):
    return fake_user_db[skip : skip + limit]

response_modelを指定してあげると、自動的にスキーマに変換してくれます。上の関数で、fake_user_dbは、List[User]という型ですが、response_modelを定義したことにより、List[schemas.UserResponse]に変換されてレスポンスが返されます。

SwaggerUIで、いろいろ試して動作を確認してみましょう。

パスオペレーション関数のdescription

パスオペレーション関数にpythonのdocstringsをつけることで、SwaggerUIにdescriptionを追加することができます。 もちろん、pythonのdocstringなので、pythonのドキュメントにもなります。積極的にdocstringsを付けていきましょう。

ここでは、例としてcreate_userにdocstringsを付けてみます。

app/endpoints/users.py

@router.post("", response_model=schemas.UserResponse)
def create_user(user_create: schemas.UserCreate):
    """
    ユーザーの作成
    """
    user = User(**user_create.model_dump())
    fake_user_db.append(user)
    return user

SwaggerUIでは、以下のようになります。

description付きのSwaggerUI

また、SwaggerUIはmarkdown記法にも対応しています。

app/endpoints/users.py

@router.post("", response_model=schemas.UserResponse)
def create_user(user_create: schemas.UserCreate):
    """
    ユーザーの作成
    - **singin_id**: ユニークなID
    - **name**: 名前
    - **password**: パスワード
    - **role**: 権限
    """
    user = User(**user_create.model_dump())
    fake_user_db.append(user)
    return user

このようにmarkdown記法で記述するとSwaggerUIでは、以下のように表示されます。

markdownで記述したdescription付きのSwaggerUI

Next: Chapter4 DBとの連携

Prev: Chapter2 ディレクトリ構成