FastAPI принимает «yes» вместо true: когда нужна строгая модель JSON

Команда включения автоматического продления должна содержать JSON true или false. Однако API принимает строки «yes», «0» и числа. На первый взгляд это удобно: Pydantic приводит распространённые формы к bool. Но при согласованном машинном контракте такое приведение скрывает ошибки клиента и усложняет проверку того, что он действительно отправляет.

Выберите строгий тип на нужной границе

Обычный bool и StrictBool отвечают на разные вопросы. Первый пытается получить логическое значение из поддерживаемого ввода. Второй требует настоящее логическое значение. Для JSON это практически полезно: true и false — самостоятельные типы, отличные от строки "true" и числа 1. Pydantic не обязан исправлять клиентский сериализатор, который потерял тип.

Не переносите это правило автоматически на URL. Query-параметры приходят текстом: строка ?enabled=true не содержит JSON-тип bool. Для query часто полезно штатное преобразование FastAPI или явно выбранные строковые значения. Строгость определяйте для каждого транспорта, а не включайте для всего приложения без разбора.

Проверьте принятие и отказ одним тестом

В примере настройка меняется через JSON-тело. Ответ содержит значение, дошедшее до обработчика. Тест отправляет обе допустимые формы и несколько типичных ошибок. В нём число 1 проверяется отдельно от true: в Python эти значения равны при обычном сравнении, но контракт JSON различает их.

Сохраните весь блок в файл и запустите Python 3.11+ в отдельном окружении с пакетами fastapi, httpx. Для моделей используется Pydantic v2; отдельный сервер для TestClient не нужен.

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

app = FastAPI()
class Renewal(BaseModel):
    enabled: StrictBool

@app.put("/renewal")
def renewal(data: Renewal):
    return data

with TestClient(app) as client:
    for value in (True, False):
        response = client.put("/renewal", json={"enabled": value})
        assert response.status_code == 200
        assert response.json()["enabled"] is value
    for value in ("true", "yes", "0", 1, 0, None):
        response = client.put("/renewal", json={"enabled": value})
        assert response.status_code == 422
        assert response.json()["detail"][0]["loc"] == ["body", "enabled"]
print("only JSON booleans accepted")

Как читать результат

Успешное преобразование не равно успешному соблюдению договора. В этом сценарии ошибка 422 полезнее молчаливого принятия строки: разработчик интерфейса видит дефект до того, как команда изменит состояние. Возвращать 500 здесь неверно, потому что сервер работает и отклоняет входные данные по заявленному правилу.

Строгий тип не решает, кому разрешено менять настройку. Проверка пользователя должна выполняться отдельно. Он также не запрещает неизвестные ключи: если команда должна отклонять лишние поля, добавьте extra="forbid" как независимое правило. В тестах хорошо иметь отдельный пример на каждое решение, чтобы отказ сразу указывал на сломанный контракт.

Как изменить существующий API

Перед включением StrictBool посмотрите примеры SDK и запросов вашего интерфейса. Некоторые языки сериализуют значение из HTML-формы строкой. Исправьте преобразование на стороне клиента и добавьте его проверку. Если вы управляете несколькими версиями клиентов, согласуйте переход: мгновенное ужесточение может превратить привычные запросы в 422.

Оставьте в OpenAPI понятное описание поля с примером JSON. При этом сама схема boolean ещё не всегда объясняет поведение всех приводящих типов: регрессионный HTTP-тест остаётся точным исполняемым договором. Существующая статья о PATCH и false объясняет сохранение уже разобранного значения; здесь мы определяем, какие значения вообще разрешено разобрать.

Следующая практика

В открытом уроке об ограничениях Pydantic вы проверите входные значения и увидите, как API возвращает ошибки формы. После этого сравните обычный bool и StrictBool на JSON-команде из статьи. Откройте урок о валидации и выполните проверку полей.

Дальше полезно связать валидацию с сохранением настройки и правами пользователя. В бесплатной программе FastAPI эти части соединяются в один API с базой и тестами. Откройте программу курса.

Продолжить на практике