コンテンツにスキップ

クエリパラメータと文字列の検証

FastAPI ではパラメータの追加情報とバリデーションを宣言することができます。

以下のアプリケーションを例にしてみましょう:

from typing import Union

from fastapi import FastAPI

app = FastAPI()


@app.get("/items/")
async def read_items(q: Union[str, None] = None):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results

クエリパラメータ qOptional[str] 型で、None を許容する str 型を意味しており、デフォルトは None です。そのため、FastAPIはそれが必須ではないと理解します。

備考

FastAPIは、 q はデフォルト値が =None であるため、必須ではないと理解します。

Optional[str] における Optional はFastAPIには利用されませんが、エディターによるより良いサポートとエラー検出を可能にします。

バリデーションの追加

qはオプショナルですが、もし値が渡されてきた場合には、50文字を超えないことを強制してみましょう。

Queryのインポート

そのために、まずはfastapiからQueryをインポートします:

from typing import Union

from fastapi import FastAPI, Query

app = FastAPI()


@app.get("/items/")
async def read_items(q: Union[str, None] = Query(default=None, max_length=50)):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results

デフォルト値としてQueryを使用

パラメータのデフォルト値として使用し、パラメータmax_lengthを50に設定します:

from typing import Union

from fastapi import FastAPI, Query

app = FastAPI()


@app.get("/items/")
async def read_items(q: Union[str, None] = Query(default=None, max_length=50)):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results

デフォルト値NoneQuery(default=None)に置き換える必要があるので、Queryの最初の引数はデフォルト値を定義するのと同じです。

なので:

q: Optional[str] = Query(default=None)

...を以下と同じようにパラメータをオプションにします:

q: Optional[str] = None

しかし、これはクエリパラメータとして明示的に宣言しています。

情報

FastAPIは以下の部分を気にすることを覚えておいてください:

= None

もしくは:

= Query(default=None)

そして、 None を利用することでクエリパラメータが必須ではないと検知します。

Optional の部分は、エディターによるより良いサポートを可能にします。

そして、さらに多くのパラメータをQueryに渡すことができます。この場合、文字列に適用される、max_lengthパラメータを指定します。

q: Union[str, None] = Query(default=None, max_length=50)

これにより、データを検証し、データが有効でない場合は明確なエラーを表示し、OpenAPIスキーマの path operation にパラメータを記載します。

バリデーションをさらに追加する

パラメータmin_lengthも追加することができます:

from typing import Union

from fastapi import FastAPI, Query

app = FastAPI()


@app.get("/items/")
async def read_items(
    q: Union[str, None] = Query(default=None, min_length=3, max_length=50)
):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results

正規表現の追加

パラメータが一致するべき正規表現を定義することができます:

from typing import Union

from fastapi import FastAPI, Query

app = FastAPI()


@app.get("/items/")
async def read_items(
    q: Union[str, None] = Query(
        default=None, min_length=3, max_length=50, pattern="^fixedquery$"
    ),
):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results

この特定の正規表現は受け取ったパラメータの値をチェックします:

  • ^: は、これ以降の文字で始まり、これより以前には文字はありません。
  • fixedquery: は、正確なfixedqueryを持っています.
  • $: で終わる場合、fixedquery以降には文字はありません.

もしこれらすべての 正規表現のアイデアについて迷っていても、心配しないでください。多くの人にとって難しい話題です。正規表現を必要としなくても、まだ、多くのことができます。

しかし、あなたがそれらを必要とし、学ぶときにはすでに、 FastAPIで直接それらを使用することができます。

デフォルト値

第一引数にNoneを渡して、デフォルト値として使用するのと同じように、他の値を渡すこともできます。

クエリパラメータqmin_length3とし、デフォルト値をfixedqueryとしてみましょう:

from fastapi import FastAPI, Query

app = FastAPI()


@app.get("/items/")
async def read_items(q: str = Query(default="fixedquery", min_length=3)):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results

備考

デフォルト値を指定すると、パラメータは任意になります。

必須にする

これ以上、バリデーションやメタデータを宣言する必要のない場合は、デフォルト値を指定しないだけでクエリパラメータqを必須にすることができます。以下のように:

q: str

以下の代わりに:

q: Union[str, None] = None

現在は以下の例のようにQueryで宣言しています:

q: Union[str, None] = Query(default=None, min_length=3)

そのため、Queryを使用して必須の値を宣言する必要がある場合は、第一引数に...を使用することができます:

from fastapi import FastAPI, Query

app = FastAPI()


@app.get("/items/")
async def read_items(q: str = Query(min_length=3)):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results

情報

これまで...を見たことがない方へ: これは特殊な単一値です。Pythonの一部であり、"Ellipsis"と呼ばれています

これは FastAPI にこのパラメータが必須であることを知らせます。

クエリパラメータのリスト / 複数の値

クエリパラメータを明示的にQueryで宣言した場合、値のリストを受け取るように宣言したり、複数の値を受け取るように宣言したりすることもできます。

例えば、URL内に複数回出現するクエリパラメータqを宣言するには以下のように書きます:

from typing import List, Union

from fastapi import FastAPI, Query

app = FastAPI()


@app.get("/items/")
async def read_items(q: Union[List[str], None] = Query(default=None)):
    query_items = {"q": q}
    return query_items

そしてURLは以下です:

http://localhost:8000/items/?q=foo&q=bar

複数のクエリパラメータの値qfoobar)をpath operation関数内で関数パラメータqとしてPythonのlistを受け取ることになります。

そのため、このURLのレスポンスは以下のようになります:

{
  "q": [
    "foo",
    "bar"
  ]
}

豆知識

上述の例のように、list型のクエリパラメータを宣言するには明示的にQueryを使用する必要があります。そうしない場合、リクエストボディと解釈されます。

対話的APIドキュメントは複数の値を許可するために自動的に更新されます。

デフォルト値を持つ、クエリパラメータのリスト / 複数の値

また、値が指定されていない場合はデフォルトのlistを定義することもできます。

from typing import List

from fastapi import FastAPI, Query

app = FastAPI()


@app.get("/items/")
async def read_items(q: List[str] = Query(default=["foo", "bar"])):
    query_items = {"q": q}
    return query_items

以下のURLを開くと:

http://localhost:8000/items/

qのデフォルトは: ["foo", "bar"] となり、レスポンスは以下のようになります:

{
  "q": [
    "foo",
    "bar"
  ]
}

listを使う

List[str]の代わりに直接listを使うこともできます:

from fastapi import FastAPI, Query

app = FastAPI()


@app.get("/items/")
async def read_items(q: list = Query(default=[])):
    query_items = {"q": q}
    return query_items

備考

この場合、FastAPIはリストの内容をチェックしないことを覚えておいてください。

例えばList[int]はリストの内容が整数であるかどうかをチェックします(そして、文書化します)。しかしlistだけではそうしません。

より多くのメタデータを宣言する

パラメータに関する情報をさらに追加することができます。

その情報は、生成されたOpenAPIに含まれ、ドキュメントのユーザーインターフェースや外部のツールで使用されます。

備考

ツールによってOpenAPIのサポートのレベルが異なる可能性があることを覚えておいてください。

その中には、宣言されたすべての追加情報が表示されていないものもあるかもしれませんが、ほとんどの場合、不足している機能はすでに開発の計画がされています。

titleを追加できます:

from typing import Union

from fastapi import FastAPI, Query

app = FastAPI()


@app.get("/items/")
async def read_items(
    q: Union[str, None] = Query(default=None, title="Query string", min_length=3)
):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results

descriptionを追加できます:

from typing import Union

from fastapi import FastAPI, Query

app = FastAPI()


@app.get("/items/")
async def read_items(
    q: Union[str, None] = Query(
        default=None,
        title="Query string",
        description="Query string for the items to search in the database that have a good match",
        min_length=3,
    ),
):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results

エイリアスパラメータ

パラメータにitem-queryを指定するとします.

以下のような感じです:

http://127.0.0.1:8000/items/?item-query=foobaritems

しかし、item-queryは有効なPythonの変数名ではありません。

最も近いのはitem_queryでしょう。

しかし、どうしてもitem-queryと正確に一致している必要があるとします...

それならば、aliasを宣言することができます。エイリアスはパラメータの値を見つけるのに使用されます:

from typing import Union

from fastapi import FastAPI, Query

app = FastAPI()


@app.get("/items/")
async def read_items(q: Union[str, None] = Query(default=None, alias="item-query")):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results

非推奨パラメータ

さて、このパラメータが気に入らなくなったとしましょう

それを使っているクライアントがいるので、しばらくは残しておく必要がありますが、ドキュメントには非推奨と明記しておきたいです。

その場合、Queryにパラメータdeprecated=Trueを渡します:

from typing import Union

from fastapi import FastAPI, Query

app = FastAPI()


@app.get("/items/")
async def read_items(
    q: Union[str, None] = Query(
        default=None,
        alias="item-query",
        title="Query string",
        description="Query string for the items to search in the database that have a good match",
        min_length=3,
        max_length=50,
        pattern="^fixedquery$",
        deprecated=True,
    ),
):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results

ドキュメントは以下のようになります:

まとめ

パラメータに追加のバリデーションとメタデータを宣言することができます。

一般的なバリデーションとメタデータ:

  • alias
  • title
  • description
  • deprecated

文字列のためのバリデーション:

  • min_length
  • max_length
  • regex

この例では、strの値のバリデーションを宣言する方法を見てきました。

数値のような他の型のバリデーションを宣言する方法は次の章を参照してください。