MENU

Django Ninjaチュートリアル⑥(リクエストボディ)

Django-Ninjaチュートリアル⑥(リクエストボディ)

前回までの記事はこちらです。

前回までの記事が読まれている前提で書いていきますので、まだ読んでいない方はこちらから読み進めて、追いついてください。

それでは始めていきましょう。

目次

リクエストボディ

今回はDjango Ninjaにおけるリクエストボディの取り扱いについてみていきます。

リクエストボディは、通常CRUD処理(「Create(作成)」、「Retrive(取得)」、 「Update(更新)」、「Delete(削除)」)に関連して、GETやPOST、PUT、PATCHで使用されます。

たとえば、POSTまたはPUTを使用してリソースを作成する場合、通常リクエストボディには作成するリソースの表現が含まれることになります。

リクエストボディを宣言するには、Django NinjaのSchemaを使用していきます。

Schemaの定義

まずはSchemaの定義をしていきます。

import datetime
from ninja import Schema

〜略〜

# add 2
class Item(Schema):
  name: str
  description: str = None
  price: float
  quantity: int

Django Ninjaが提供するSchemaを継承したclassとして定義します。
また、それぞれの項目に型を定義します。

リクエストボディでデフォルト値をNoneにする場合、この項目(ここではdescription)はオプショナルな項目となります。
APIの中で引数として渡さない場合でも、正常に機能します。

パラメータとしての宣言

from ninja import NinjaAPI, Path
from example.Schema.api_v2_schema import PathDate, Item # add
from datetime import date

app_v2 = NinjaAPI(
  title = "Django Ninja Sample App2",
  version = "1.0.1"
)

〜略〜

# add 6
@app_v2.get("/items")
def create(request, item: Item):
  return item

APIの定義をしていきます。
引数としてitemを渡していますが、型定義として、別ファイルで設定したItem Schemaにより型定義をしています。

そして、itemが最終的にリターンされる時に、Schemaに基づき、型チェックとバリデーションが機能します。

これにより、Django Ninajaでは、型宣言をするだけで、次のことをしてくれます。

  1. リクエストボディをJSONとして読み取る
  2. 対応する型を変換する(必要な場合)
  3. 渡されたデータを検証する
    ※無効なデータの場合、適切でかつ意味のあるエラーが返される
    ※正しくないデータの正確な箇所とその内容が示される
  4. 受け取ったデータをitemパラメータに渡す
    関数内でSchemaとして宣言したItemを割り当てているため、すべての属性とその型に対するすべてのエディターサポート(補完など) も利用できる
  5. JSONスキーマの定義を生成する
  6. これらのスキーマは、生成されたOpenAPIスキーマの一部となり、自動ドキュメントUIによって使用される

OpenAPIの確認

OpenAPIで生成された自動ドキュメントを確認してみます。

生成されたOpenAPIの自動ドキュメント

ページの下部にSchemasが表示されています。

このように宣言したSchemaもAPIの自動生成時に併せて表示されるようになっています。

また、このJSON Schemaは実際のAPIドキュメント内でも使用されていることがわかります。

自動生成ドキュメント内でのJSONの使用

リクエストボディ+パスパラメータ

次に見ていくのは、リクエストボディとパスパラメータの併用パターンです。

Django Ninjaでは、パスパラメータとリクエストボディを同時に宣言することができます。

Django Ninjaでは、パスパラメータに渡された値は、一致する関数パラメータに渡される必要があります。
また、Schemaで宣言した関数パラメータは、リクエストボディから取得する必要があります。

例を見てみましょう。

from ninja import NinjaAPI, Path
from example.Schema.api_v2_schema import PathDate, Item
from datetime import date

app_v2 = NinjaAPI(
  title = "Django Ninja Sample App2",
  version = "1.0.1"
)

〜略〜

# add 7
@app_v2.put("/items/{item_id}")
def update_item(request, item_id: int, item: Item):
  return {"item_id": item_id, "item": item}

上記の例では、パスパラメータとしてitem_idを設定しています。
これにより、関数内ではitem_idに対し、int型の定義をしています。
また、先に設定しておいたSchemaであるItemを、引数itemに割り当てています。

このように、パスパラメータで渡した引数とリクエストボディとして送信する引数は分けて取り扱う必要があります。

リクエストボディ+パスパラメータ+クエリパラメータ

Django Ninjaでは、リクエストボディ、パスパラメータそしてクエリパラメータのすべてを同時に宣言することもできます。

Django Ninjaはそれぞれを認識し、適切な場所からデータを取得します。

from ninja import NinjaAPI, Path
from example.Schema.api_v2_schema import PathDate, Item
from datetime import date

app_v2 = NinjaAPI(
  title = "Django Ninja Sample App2",
  version = "1.0.1"
)

〜略〜

# add 7(change)
@app_v2.put("/items/{item_id}")
def update_item(request, item_id: int, item: Item, q: str):
  return {"item_id": item_id, "item": item.dict(), "q": q}

上記の例をDjango Ninjaでは、以下のように処理されます。

  1. 関数パラメータがパスパラメータとしても宣言されている場合は、パスパラメータとして使用される
  2. 関数パラメータが単数型(singular type)(例えば、intfloatstrboolなど)の場合は、クエリパラメータとして解釈される
  3. 関数パラメータがSchema(またはPydanticBaseModel)による型定義がされている場合は、リクエストボディとして解釈される

最後に

今回は、リクエストボディとパスパラメータ、クエリパラメータの関係についてまとめてみました。

公式ドキュメントで示されている例を見ると、リクエストボディはSchemaとしての宣言をして使う形となります。
また、これによりパスパラメータとクエリパラメータとの判断もしやすくなります。

具体的なユースケースにはまだチャレンジしていないので、後々、これらの内容を踏まえて具体的なAPIの構築をしてみたいと思いました。

Django REST Frameworkで作成してきたAPIもこれだとサクッと作れてしまいそうな気もしていきました。

ブログシステムなどを例に記事にまとめてみてもいいかもしれません。

それでは今回はここまでとします。
次回以降もよろしくお願いします。

Django-Ninjaチュートリアル⑥(リクエストボディ)

この記事が気に入ったら
フォローしてね!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

はじめまして、ふじです。
Python、Django、FastAPI、React.js、Next.jsを学習している、ずっと文系のプログラミング独学者です。

目次