4

Pydantic 2.0 seems to have drastically changed.

Previously with FastAPI and Pydantic 1.X I could define the schema like this, where receipt is optional:

class VerifyReceiptIn(BaseModel):
    device_id: str
    device_type: DeviceType
    receipt: Optional[str]

Then in FastAPI endpoint I could do this:

@router_verify_receipt.post(
    "/",
    status_code=201,
    response_model=VerifyReceiptOut,
    responses={201: {"model": VerifyReceiptOut}, 400: {"model": HTTPError}},
)
async def verify_receipt(body: VerifyReceiptIn):
    auth_service = AuthService()
    ...

And the unit test without receipt in body was fine with it, but now with Pydantic 2.0 it's failing. Now it claims that Receipt is required and throws a 422 error.

response = await client.post(
            "/verify-receipt/",
            headers={"api-token": "abc123"},
            json={
                "device_id": "u1",
                "device_type": DeviceType.ANDROID.value,
            },
        )

But this is why we had Optional. Why do I have to pass receipt=None in body? This is not ideal as it will break everything on production. Is there a way around this? Thanks

Houman
  • 64,245
  • 87
  • 278
  • 460
  • 3
    [This answer](https://stackoverflow.com/a/76467243/19770795) may be of interest to you for understanding, what was going in Pydantic v1. The fact that you could omit values for `Optional[T]` fields even though you never explicitly defined a **default** for them was inconsistent behavior. I for one am very glad they [decided](https://github.com/pydantic/pydantic/issues/6475#issuecomment-1623230665) to change this in v2 and force people to explicitly define defaults. If you want `receipt` to default to `None` then specify that in the model: `receipt: Optional[str] = None` – Daniil Fajnberg Jul 14 '23 at 20:34
  • In addition to @DaniilFajnberg's comment above, you might find [this](https://stackoverflow.com/a/72289969/17865804) and [this](https://stackoverflow.com/a/73261442/17865804) helpful as well. – Chris Jul 15 '23 at 05:14
  • Ah Thanks guys. I understand now. Maybe you would like to add an answer with `receipt: Optional[str] = None` and I accept. I just tested it and it works. In the hindsight it was obvious, but didn't understand it yesterday. – Houman Jul 15 '23 at 06:22

0 Answers0