- Day 69:POST API ― 「外から送られてきたデータを、ちゃんと受け止める」
- POST APIとは ― 「データを送ってもらうための入り口」
- リクエストボディとは ― 「APIに渡される中身のデータ」
- データモデル(Pydantic) ― 「JSONの形をPythonで表現する」
- POST APIでデータモデルを受け取る ― 「JSONがそのままPythonオブジェクトになる」
- バリデーション ― 「おかしなデータを、入口でちゃんと止める」
- Day 69ミニテンプレート ― POST+モデル+バリデーションの基本セット
- Day 69のまとめ ― 「APIの入口で、データをちゃんと“選別”できるようになる」
Day 69:POST API ― 「外から送られてきたデータを、ちゃんと受け止める」
Day 69では、FastAPI入門の続きとして、 POST API をテーマに進めていきます。
キーワードはこの4つです。
- POST API
- リクエストボディ
- データモデル
- バリデーション
昨日のDay 68では、GET APIを通して「情報を返す」側を体験しました。 今日はその逆、「クライアントから送られてくるデータを受け取り、処理する」 側に回ります。
ここを理解できると、 「フォームから送信されたデータを保存する」「外部サービスからJSONを受け取る」 といった、現実のWeb/API開発にぐっと近づいていきます。
POST APIとは ― 「データを送ってもらうための入り口」
GETとPOSTの役割の違いを整理する
まずは、HTTPメソッドの役割をざっくり整理しておきます。
- GET:情報を取得する(読む)
- POST:新しい情報を送る(作る・登録する)
もちろん、POSTは「作る」だけでなく、 「検索条件を送る」「処理の指示を送る」などにも使われますが、 基本的には 「何かを送る」ためのメソッド と考えておくと分かりやすいです。
FastAPIでのPOST APIの基本形
FastAPIでは、 @app.post("/path") というデコレータで、POST APIを定義します。
from fastapi import FastAPI
app = FastAPI()
@app.post("/echo")
def echo():
"""
とてもシンプルなPOST APIの例です。
まだリクエストボディは扱っていません。
"""
return {"message": "POSTでアクセスされました。"}
Pythonただ、これだけだと「POSTされたこと」しか分かりません。 本番のAPIでは、リクエストボディ(送られてきたJSONなど) を受け取って処理することがほとんどです。
リクエストボディとは ― 「APIに渡される中身のデータ」
リクエストボディのイメージ
リクエストボディ とは、
クライアント(ブラウザや他のサービス)が、 APIに対して送ってくる「中身のデータ」のこと
です。
例えば、ユーザー登録APIを考えてみましょう。
{
"name": "Taro",
"email": "taro@example.com",
"age": 25
}
JSONこういったJSONが、HTTPリクエストの「ボディ部分」に入って送られてきます。 POST APIは、このボディを受け取って、 「データベースに保存する」「バリデーションする」「レスポンスを返す」 といった処理を行います。
FastAPIでリクエストボディを受け取る基本形
FastAPIでは、 関数の引数に「データモデル」を指定することで、リクエストボディを受け取ります。
ここで登場するのが Pydanticモデル です。
データモデル(Pydantic) ― 「JSONの形をPythonで表現する」
Pydanticモデルとは
FastAPIは内部で Pydantic というライブラリを使っていて、 これを使うことで、
- リクエストボディのJSONを、Pythonのオブジェクトとして扱える
- 型ヒントに基づいて、自動でバリデーションしてくれる
- ドキュメント(OpenAPI)にも反映してくれる
という、かなり嬉しいことが起こります。
まずは、Pydanticモデルを定義してみましょう。
# day69_post_api.py
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class UserCreate(BaseModel):
"""
ユーザー作成用のリクエストボディを表すデータモデルです。
クライアントから送られてくるJSONの形を、このクラスで定義します。
"""
name: str
email: str
age: int | None = None # 年齢は任意項目とします
Pythonここでやっていることは、
BaseModelを継承したUserCreateクラスを作るname,email,ageという属性を定義する- 型ヒント(
str,int | None)で、データの型を指定する - デフォルト値
Noneを指定することで、「任意項目」にできる
という、まさに「JSONの形をPythonで表現する」作業です。
POST APIでデータモデルを受け取る ― 「JSONがそのままPythonオブジェクトになる」
ユーザー作成APIの例
この UserCreate モデルを使って、 実際にPOST APIを作ってみます。
@app.post("/users")
def create_user(user: UserCreate):
"""
ユーザー作成用のPOST APIです。
リクエストボディのJSONを UserCreate モデルとして受け取ります。
例として、送られてきた内容をそのままレスポンスとして返します。
本来はここでDB保存などを行います。
"""
# user は UserCreate のインスタンスです。
# user.name, user.email, user.age で各値にアクセスできます。
print(f"[POST] 新しいユーザー: name={user.name}, email={user.email}, age={user.age}")
# ここでは、簡単なメッセージと一緒に返してみます。
return {
"message": "ユーザーを受け取りました。",
"user": user, # PydanticモデルはそのままJSONに変換されます。
}
Pythonここでのポイントは、
- 関数の引数
user: UserCreateが、リクエストボディを受け取る役割を持つ - クライアントから送られてきたJSONが、自動的に
UserCreateインスタンスに変換される user.nameやuser.emailのように、Pythonのオブジェクトとして扱える- 戻り値に
userを含めると、Pydanticが自動でJSONに変換してくれる
というところです。
実際のリクエスト例(イメージ)
例えば、次のようなJSONをPOSTするとします。
{
"name": "Taro",
"email": "taro@example.com",
"age": 25
}
JSONこのとき、FastAPIは、
- JSONを受け取る
UserCreateの定義に基づいて、型チェック・バリデーションを行う- 問題なければ
user: UserCreateに変換して関数に渡す
という流れで処理してくれます。
バリデーション ― 「おかしなデータを、入口でちゃんと止める」
型ヒントによる基本的なバリデーション
Pydanticモデルに型ヒントを書いておくと、 FastAPIは自動的にバリデーションを行ってくれます。
例えば、
name: strに対して、数値が送られてきたらエラーage: int | Noneに対して、文字列が送られてきたらエラー
という具合です。
この「型に合わないデータは受け付けない」という仕組みが、 APIの安全性と信頼性をぐっと高めてくれます。
もう少し踏み込んだバリデーション(長さ・形式など)
Pydanticは、もう少し細かいバリデーションも書けます。
例えば、「メールアドレスの形式をチェックしたい」という場合。
from pydantic import BaseModel, EmailStr
class UserCreate(BaseModel):
"""
メールアドレスの形式チェックを含んだユーザーモデルの例です。
EmailStr 型を使うことで、メール形式のバリデーションが自動で行われます。
"""
name: str
email: EmailStr # メールアドレス形式をチェックしてくれる型
age: int | None = None
PythonEmailStr を使うと、
taro@example.com→ OKnot-an-email→ バリデーションエラー
というように、形式チェックを自動で行ってくれます。
バリデーションエラーが起きたとき
もし、バリデーションに失敗した場合、 FastAPIは自動的に 400 Bad Request とともに、 「どの項目がどうおかしいのか」をJSONで返してくれます。
これは、APIを使う側にとってもとても親切で、 「何が間違っているのか」をすぐに理解できるようになります。
Day 69ミニテンプレート ― POST+モデル+バリデーションの基本セット
最後に、今日の内容をひとまとめにした POST API入門テンプレート を載せておきます。
# day69_post_api_template.py
from fastapi import FastAPI
from pydantic import BaseModel, EmailStr
app = FastAPI()
class UserCreate(BaseModel):
"""
ユーザー作成用のリクエストボディモデルです。
name: 必須の文字列
email: メールアドレス形式の必須文字列
age: 任意の整数
"""
name: str
email: EmailStr
age: int | None = None
@app.get("/")
def read_root():
"""
簡単なウェルカムメッセージを返すGET APIです。
"""
return {"message": "Day 69: POST API 入門へようこそ"}
@app.post("/users")
def create_user(user: UserCreate):
"""
ユーザー作成用のPOST APIです。
リクエストボディのJSONを UserCreate として受け取り、
バリデーション済みのデータとして扱います。
"""
# user はバリデーション済みの UserCreate インスタンスです。
print(f"[POST] 新規ユーザー: name={user.name}, email={user.email}, age={user.age}")
# 本来はここでDB保存などを行いますが、今回は受け取った内容をそのまま返します。
return {
"message": "ユーザーを登録しました(仮)。",
"user": user,
}
Pythonこのファイルを保存して、
bash
uvicorn day69_post_api_template:app --reload
と実行すれば、
GET /でウェルカムメッセージPOST /usersで、UserCreateに基づいたリクエストボディの受け取り&バリデーション
を試すことができます。
Day 69のまとめ ― 「APIの入口で、データをちゃんと“選別”できるようになる」
今日の主役は、
- POST API:クライアントからデータを送ってもらうための入り口
- リクエストボディ:JSONなどの「中身のデータ」
- データモデル(Pydantic):リクエストボディの形をPythonで表現するクラス
- バリデーション:おかしなデータを入口で止める仕組み
でした。
FastAPIとPydanticを組み合わせることで、
- 「どんな形のデータを受け付けるか」を、コードとして明確にできる
- 型ヒントに基づいて、自動でバリデーションしてくれる
- エラー時のレスポンスも、分かりやすいJSONで返してくれる
という、かなり心強い環境が整います。
APIは「誰かからデータを受け取る窓口」でもあり、 その窓口で 「何でもかんでも受け入れる」のではなく、 「ちゃんとしたデータだけを通す」 ことが、とても大切です。
Day 69で学んだPOST+モデル+バリデーションの組み合わせは、 そのための、静かだけれど強力な“フィルター”になってくれます。
