MongoDb with FastAPI

15,202

Solution 1

I believe you already got your answers in the issue forums of the Fastapi project on Github: Issue 452 (closed). But I'll recap the solutions here for future reference:

In short, you can use either motor or mongoengine, Fastapi supports both and you can reuse a global client object that's started and ended with your app process.

Some context details to (hopefully) clarify these technologies and their relationships:

The official MongoDB driver for Python is pymongo. Under the hoods, both MongoEngine and Motor use Pymongo. Pymongo implements a direct client for MongoDB (daemons) and offers a Python API to make requests.

If you wanted to, you could use pymongo with Fastapi directly. (On th SQL side of things, this would be equivalent to using psycopg2 in Flask directly without going through something like SQLAlchemy.)

MongoEngine is an ODM (Object-Document Mapper). It offers a Python object-oriented API that you can use in your application to work more comfortably and when it comes to the actual DB requests, MongoEngine will use pymongo.

Motor is a wrapper for pymongo that makes it non-blocking (allowing async/await). It uses an event-loop, either through Tornado or through asyncio. If you are using Fastapi with uvicorn, uvicorn will implement async functionality with uvloop. In short, using Motor with FastAPI, async should "just work". Unfortunately, Motor does not implement an ODM. In this sense it is more similar to pymongo.

Fastapi handles the requests from clients (using Starlette), but it will let you implement your own connection to MongoDB. So you are not restricted to any particular choice, but you are mostly on your own (a la Flask).

You can use the startup/shutdown hooks of your FastAPI app to start/stop your Motor/MongoEngine client. You don't need to worry about your client object not persisting due to multiprocess issues, because Fastapi is single-threaded.

@app.on_event("startup")
async def create_db_client():
    # start client here and reuse in future requests


@app.on_event("shutdown")
async def shutdown_db_client():
    # stop your client here

An example implementation of motor with Fastapi can be found here.

Solution 2

I recently created an Async Mongo ODM well suited for FastAPI: ODMantic.

app = FastAPI()
engine = AIOEngine()

class Tree(Model):
    """This model can be used either as a Pydantic model or 
       saved to the database"""
    name: str
    average_size: float
    discovery_year: int

@app.get("/trees/", response_model=List[Tree])
async def get_trees():
    trees = await engine.find(Tree)
    return trees

@app.put("/trees/", response_model=Tree)
async def create_tree(tree: Tree):
    await engine.save(tree)
    return tree

You can have a look to the FastAPI example for a more detailed example.

Share:
15,202

Related videos on Youtube

Ayush Singh
Author by

Ayush Singh

Updated on June 04, 2022

Comments

  • Ayush Singh
    Ayush Singh almost 2 years

    I am playing around with FastAPI a bit and wanted to connect it to a MongoDB database. I however am confused which ODM to choose between motor which is async and mongoengine. Also, in the NoSQL example here they have created a new bucket and also the called the code to connect to db every time it is used. However, both motor and mongoengine seem to prefer a global connection. So what would be a good way to connect to mongodb?