MongoDb with FastAPI

Ayush Singh picture Ayush Singh · Aug 19, 2019 · Viewed 7.5k times · Source

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?

Answer

Sergio Chumacero picture Sergio Chumacero · Oct 4, 2019

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.