I am trying to figure out how to update my FastAPI app after from Pydantic v1 to Pydantic v2.
Before I had code that worked perfectly fine:
class ObjectId(bson.ObjectId):
@classmethod
def __get_validators__(cls):
yield cls.validate
@classmethod
def validate(cls, value):
if isinstance(value, str):
try:
return bson.ObjectId(value)
except bson.errors.InvalidId:
raise ValueError("Invalid ObjectId")
elif isinstance(value, bson.ObjectId):
return value
else:
raise TypeError("ObjectId required")
app = FastAPI()
@app.get("/test")
def test(id: ObjectId) -> bool:
return True
However, when I try to migrate to FastAPI V2:
import bson
from typing import Annotated
from pydantic import (
field_validator,
PlainSerializer,
WithJsonSchema,
BeforeValidator,
TypeAdapter,
)
from fastapi import FastAPI
ObjectId = Annotated[
bson.ObjectId,
BeforeValidator(lambda x: bson.ObjectId(x) if isinstance(x, str) else x),
PlainSerializer(lambda x: f"{x}", return_type=str),
WithJsonSchema({"type": "string"}, mode="validation"),
WithJsonSchema({"type": "string"}, mode="serialization"),
]
# Casting from str to ObjectId - WORKS
ta = TypeAdapter(
ObjectId,
config=dict(arbitrary_types_allowed=True),
)
ta.validate_python("5f7f9f0c2a0e0b0001d5b3d0")
ta.json_schema()
# Use ObjectId as a query parameter in FastAPI - FAILS:
app = FastAPI()
@app.get("/test")
def test(id: ObjectId) -> bool:
return True
I get the following error message:
fastapi.exceptions.FastAPIError: Invalid args for response field! Hint: check that <class 'bson.objectid.ObjectId'> is a valid Pydantic field type. If you are using a return type annotation that is not a valid Pydantic field (e.g. Union[Response, dict, None]) you can disable generating the response model from the type annotation with the path operation decorator parameter response_model=None. Read more: https://fastapi.tiangolo.com/tutorial/response-model/
I am a bit confused, because it seems that the problem is not with a response model (which is bool
in the example), but with a custom type in query parameter.
I also checked other suggested approaches, for example:
- What is the new way to declare Mongo ObjectId with PyDantic v2.0^?
- Using bson.ObjectId in Pydantic v2 <- btw, duplicate
There, it is suggested an alternative approach to introduce a custom annotation type, however, it still does not work for me.
I also did not find any relevant in the FastAPI documentation about query parameters and a list of Extra Data Types.
I would highly appreciate if you could help to find a possible solution.