Python WebAcademy Blog

FastAPIの変更は0.156まで続く。JSONのnullと省略を区別するようになったニュースを初心者向けに解説

|

先日お伝えしたFastAPIの連続リリースは、その後も続き、2026年10月21日には0.156.4に達しました。0.151.0では、JSONで送られたnullと、項目を省略した場合をはっきり区別するように変わっています。新旧の版で同じAPIを呼んだ結果とともに、nullと省略の違い、上げる前に確かめたい点を整理します。

先日の記事で、FastAPIが3日間で0.144から0.150まで版を重ね、HTMLフォームの扱いが大きく変わったことをお伝えしました。その後も公開は続き、2026年10月21日には0.156.4に達しています。

今回の続報で特に大事なのが、0.151.0の変更です。JSONで送られてきたnullと、項目そのものを省略した場合を、はっきり区別するようになりました。

nullも省略も、どちらも値がないのだから同じでは?と思う方もいるでしょう。実はこの2つは、APIの設計ではまったく違う意味を持つことがあります。

今回は、新旧の版で同じAPIを呼びながら、この違いを確かめていきます。

まずは0.151から0.156で何が変わったのか

最初に、前回の記事以降に公開された版の主な変更を表にまとめます。内容は、FastAPIの公式リポジトリにあるリリースノートにもとづいています。

版 公開日 主な変更
0.151.0 10月20日 JSONのnullと省略を区別する
0.152.0 10月20日 ヘッダーのモデルの検証エラーで、HTTPのヘッダー名を表示する
0.153.0 10月20日 複数のフォームモデルのUnionにも、フォームの新しい扱いを適用
0.154.0 10月20日 リクエストの引数にPydanticの検証オプションを追加
0.155.0 10月20日 非推奨だった**extraを削除し、知らないキーワード引数はTypeErrorに
0.156.0〜0.156.4 10月20日〜21日 Pydanticのフィールド情報の引き継ぎに関する修正

0.151.0と0.155.0は、リリースノートで互換性を壊す変更として扱われています。前回の記事で取り上げた0.150.0の公開と同じ10月20日のうちに、さらに6つの版が出ていたことになります。

フォームの扱いが変わった前回の内容は、こちらで紹介しています。【関連記事】FastAPIが3日で0.150へ。HTMLフォームの扱いが変わった

nullと省略は何が違うのか

JSONでは、値がないことを2つの方法で表せます。項目にnullを入れる方法と、項目そのものを書かない方法です。

送り方 JSONの例 よくある意味
nullを送る {"theme": null} この値を空にしてほしい
項目を省略する {} この値には触れないでほしい

たとえば、設定を一部だけ変える更新APIを考えてみてください。テーマの設定を消したいのか、テーマには触れていないのかは、まったく別の指示ですよね。

この2つを同じに扱うと、利用者の意図を取り違えてしまいます。Pydantic 2.14で正式になったMISSINGも、同じ問題を解決するための仕組みでした。【関連記事】Pydantic 2.14がリリース

0.151.0で何が変わったのか

リリースノートによると、0.151.0から、個別のBodyの引数でnullが送られた場合は、Noneとして検証されるようになりました。Noneを受け付ける型なら、そのままNoneになります。

一方で、Noneを受け付けない型の場合は、既定値が決められていてもエラーになります。既定値が使われるのは、値が省略されたときだけです。

新旧の版で同じAPIを呼んでみた

実際に試してみましょう。テーマと音量という2つの設定を、部分的に更新するAPIを用意しました。themeはNoneも受け付け、volumeは整数だけを受け付けます。

from typing import Annotated

from fastapi import Body, FastAPI
from fastapi.testclient import TestClient

app = FastAPI()


@app.patch("/settings")
def update(
    theme: Annotated[str | None, Body()] = "light",
    volume: Annotated[int, Body()] = 50,
):
    return {"theme": theme, "volume": volume}


client = TestClient(app)
print(client.patch("/settings", json={}).json())
print(client.patch("/settings", json={"theme": None}).json())
res = client.patch("/settings", json={"volume": None})
print(res.status_code, res.json()["detail"][0]["msg"] if res.status_code == 422 else res.json())

0.150.0と0.156.4を、それぞれ新しい仮想環境に入れて、手元のPython 3.11で実行した結果です。動作に関係のない警告の行は省いています。

FastAPI 0.150.0
{'theme': 'light', 'volume': 50}
{'theme': 'light', 'volume': 50}
200 {'theme': 'light', 'volume': 50}

FastAPI 0.156.4
{'theme': 'light', 'volume': 50}
{'theme': None, 'volume': 50}
422 Input should be a valid integer

1行目の、何も送らない場合は、どちらの版でも既定値が使われています。違いが出たのは、2行目と3行目です。

0.150.0では、nullが既定値で上書きされていた

0.150.0では、themeにnullを送っても、既定値のlightに置き換えられていました。テーマを消したいという利用者の意図が、黙って無視されていたわけです。

0.156.4では、themeにnullを送ると、きちんとNoneになりました。そして、Noneを受け付けないvolumeにnullを送ると、422のエラーで知らせてくれます。

リリースノートには、nullを送って既定値を使ってもらっていたクライアントは、代わりに値を省略するよう書かれています。APIを呼ぶ側のコードも、あわせて確認しておきましょう。

部分更新では、モデルとexclude_unsetが便利

実際の部分更新APIでは、Pydanticのモデルで受け取り、model_dump(exclude_unset=True)で送られてきた項目だけを取り出す書き方がよく使われます。0.156.4で試してみました。

from fastapi import FastAPI
from fastapi.testclient import TestClient
from pydantic import BaseModel


class SettingsUpdate(BaseModel):
    theme: str | None = None
    volume: int | None = None


app = FastAPI()


@app.patch("/settings")
def update(data: SettingsUpdate):
    return data.model_dump(exclude_unset=True)


client = TestClient(app)
print(client.patch("/settings", json={"volume": 80}).json())
print(client.patch("/settings", json={"theme": None}).json())

実行結果は次のとおりです。

{'volume': 80}
{'theme': None}

1つ目は、送られてきたvolumeだけが取り出され、触れていないthemeは含まれていません。2つ目は、明示的にnullを送ったthemeが、空にしたいという指示として残りました。

あとは、この結果に含まれる項目だけをデータベースに書き込めば、利用者の意図どおりの部分更新ができます。nullと省略を区別する考え方が、そのまま形になった書き方です。

JSONの本体全体がnullの場合

リリースノートによると、Body(embed=True)を使う場合や、本体の引数が複数ある場合のように、JSONのオブジェクトを期待しているところへ、本体全体としてnullを送ると、検証エラーになるようになりました。

これも、値がないことを、あいまいなまま受け流さないための変更です。JSONの基本的な扱いについては、こちらで紹介しています。【関連記事】PythonでJSONを扱う方法

知らないキーワード引数はエラーに

もう1つの互換性を壊す変更が、0.155.0です。Path、Query、Header、Cookie、Body、Form、Fileに渡せた、非推奨の**extraという仕組みが削除されました。

これまでは、知らない名前のキーワード引数を渡しても、黙って受け入れられていました。0.155.0からは、TypeErrorになります。

実際に、Query(custom="value")を2つの版で実行してみました。

版 結果
0.150.0 エラーにならずに受け入れられた
0.156.4 TypeError: Query() got an unexpected keyword argument 'custom'

リリースノートによると、OpenAPIの仕様書に独自の情報を加えたい場合は、Query(json_schema_extra={"custom": "value"})のように書き換えます。引数の名前を打ち間違えたときにも、エラーで教えてもらえるようになったのは嬉しいところです。

私は10年ほどエンジニアとして開発に関わってきましたが、引数の名前のちょっとした打ち間違いが黙って無視され、設定が効かない原因を探して半日つぶしたことがあります。間違いをその場でエラーにしてくれる変更は、長い目で見ると開発をずっと楽にしてくれます。

そのほかの変更

ほかにも、いくつかの改善が入っています。代表的なものを紹介します。

0.152.0では、ヘッダーをまとめたモデルの検証エラーに、Pythonのフィールド名ではなく、実際のHTTPのヘッダー名が表示されるようになりました。リリースノートの例では、int_valではなくint-valと表示されます。

0.154.0では、リクエストの引数に、Pydanticの検証オプションを指定できるようになりました。0.156.0から0.156.4までは、PydanticのField()で付けた情報が、正しく引き継がれるようにする修正が続いています。

FastAPIそのものの基本は、こちらで紹介しています。【関連記事】PythonのFastAPIとは?

上げる前にやっておきたいこと

最後に、0.150以前から上げる場合に確かめておきたいことを整理します。前回の記事のフォームの確認とあわせて見てください。

順番 確認すること
1 JSONでnullを送って既定値を使ってもらうクライアントがないか
2 Noneを受け付けない型に、nullが届く可能性がないか
3 Queryなどに、知らない名前のキーワード引数を渡していないか
4 ヘッダーの検証エラーの文面に頼ったテストがないか
5 使うFastAPIの版をrequirements.txtなどで固定しているか

以前、APIの仕様書にnullと省略の違いを書かずにいたせいで、呼ぶ側のチームと解釈が食い違い、データを消してしまう寸前までいったことがあります。nullと省略をどう扱うかは、APIを作る側と使う側で必ず言葉にしておくことをおすすめします。

まとめ

FastAPIの連続リリースは、2026年10月21日の0.156.4まで続きました。0.151.0ではJSONのnullと省略を区別するようになり、0.155.0では知らないキーワード引数がTypeErrorになっています。

値を空にしたいのか、触れたくないのか。この違いをフレームワークがきちんと区別してくれるのは、更新APIを作るうえで大きな安心材料です。上げる前に、上の確認ポイントを一度見直してみてください。

ここまでお読みいただきありがとうございました。

参考情報

次のアクション

記事で学んだ内容を実際に動かしてみよう

Python WebAcademyでは、ブラウザ上でコードを書きながら基礎から実践まで体系的に学べます。

Python WebAcademyの学習画面

あわせて読む

関連記事

ブログ一覧へ

Python学習ロードマップ

まずはこの3講座から

記事で気になったテーマを、順番に手を動かしながら学べます。

ロードマップを見る