Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MongoDb with FastAPI

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?

like image 260
Ayush Singh Avatar asked Aug 19 '19 19:08

Ayush Singh


People also ask

Can I use MongoDB with FastAPI?

FastAPI can also be integrated with any NoSQL . Here we'll see an example using Couchbase, a document based NoSQL database. You can adapt it to any other NoSQL database like: MongoDB.

Is FastAPI better than flask?

When you're building APIs, FastAPI will be a better choice than Flask, especially when microservices are taken into consideration. The only argument for choosing Flask in this case would be if your organization already has a lot of tooling built around that framework.

How use MongoDB with Python?

The first step to connect python to Atlas is MongoDB cluster setup. Next, create a file named pymongo_test_insert.py in any folder to write pymongo code. You can use any simple text editor like Textpad/Notepad. Use the connection_string to create the mongoclient and get the MongoDB database connection.

Is PyMongo async?

Is PyMongo asyncronous? According to their documentation (https://pymongo.readthedocs.io/en/stable/faq.html), PyMongo fully supports Gevent: So yes, if implemented correctly, PyMongo is able to use an asynchronous framework like Gevent.


2 Answers

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.

like image 114
Sergio Chumacero Avatar answered Oct 20 '22 02:10

Sergio Chumacero


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.

like image 10
art049 Avatar answered Oct 20 '22 02:10

art049