nayan32biswas / mongodb-odm

MongoDB-ODM, NOSQL databases in Python, designed for simplicity, compatibility, and robustness.
https://mongodb-odm.readthedocs.io
MIT License
19 stars 1 forks source link

Pydantic schema validation incompatible to mongodb-odm Document? #31

Open Magnati opened 4 months ago

Magnati commented 4 months ago

Hey,

it seems your Document class kills the ability of Fastapi to use Pydantic models directly to check the output schema of an endpoint. At least it leads to an error during the creation of the openapi.json. Resulting in an error when checking 0.0.0.0:4567/docsfor the swagger UI: Bildschirmfoto 2024-07-05 um 14 33 42

Is this a known issue or a false usage error on my site? Minimal reproducable.


import os
from typing import Optional

import uvicorn
from bson import ObjectId
from fastapi import FastAPI, status
from mongodb_odm import Document, connect

# model schemas
class StarfleetShip(Document):
    name: str
    registry: str
    phaser: int
    torpedo_launcher: int

    class ODMConfig(Document.ODMConfig):
        allow_inheritance = True

class StarfleetShipExtend(StarfleetShip):
    captain_name: Optional[str] = None
    warp_std: Optional[float] = None
    warp_max: Optional[float] = None

    class ODMConfig(Document.ODMConfig):
        allow_inheritance = False
        collection_name = "starfleet_ship"

# ---

connect(os.environ.get("MONGO_URL", "mongodb://localhost:27017/testdb"))

app = FastAPI()
app.title = 'MongoDB-ODM Test Service'

@app.get('/ship',
            status_code=status.HTTP_200_OK,
            response_model=list[StarfleetShipExtend],  # if commented out, the app will start and the openapi.json is created
            )
def get_ships():
    """Get all ships."""
    return list(StarfleetShipExtend.find())

@app.get('/ship/{object-id}', status_code=status.HTTP_200_OK)
def get_ship_detail(object_id: str) -> StarfleetShipExtend:  # if commented result type away, the app will start and the openapi.json is created
    """Get one ship."""
    return StarfleetShipExtend.find_one({'_id': ObjectId(object_id)})

def main():
    uvicorn.run('main:app', host="0.0.0.0", port=4567)

if __name__ == '__main__':
    main()
nayan32biswas commented 4 months ago

Hi @Magnati, this is an issue of Pymongo ObjectId. The ObjectId is not JSON serializeable. If we convert it to string type then the issue will be solved but we will lose all of the features of the ObjectId, which we don't want to.

Not only the API documentation but also the respective API will through an error that the object is not JSON serializable.