circuit

How to use FastAPI with MongoDB

An easy way to serve your database documents.




FastAPI is a very cool open-source framework to construct API using Python. Its syntax is similar to Flask, so if you use it, you should not have any trouble learning it.

It has some advantages over Flask, such as:

  • It is fast (as compared with Flask);

  • It has automatic docs (OpenAPI);

  • It can use async functions;

  • It has support for websocket;

  • And many more;

It is a relative new development (< 2 years), but it has already 20k stars on Github.

You can learn more about this framework in these articles:

  1. Introducing FastAPI
  2. You Should Start Using FastAPI Now

MongoDB is a document database where you can store data directly in JSON format. It is very simple to start and create an application using MongoDB. Yet it is a powerful tool.

In this article, I’m going to show you how to implement an API for a MongoDB database.

Note: this tutorial was done with MongoDB version 4.4 and Python 3.8, in a machine with Ubuntu 20.04.

Installing

You can install MongoDB following the instructions for your operating system here.

You can use pip to install FastAPI:

pip install fastapi

To connect with the MongoDB database, we’re going to use the PyMongo package:

pip install pymongo

Since FastAPI uses Starlette framework for the web requests, we have to install an ASGI server as well:

pip install uvicorn

A basic application

We can create a basic application to see if everything is installed correctly.

The first step is to create the FastAPI object:

app = FastAPI()

After that, we can start creating the endpoints we need. The syntax is simple: is a decorator with the name of the HTTP request, with the path as the parameter. That is:

@app.get('/')
async def index():
    return {'hello': 'world'}

And that is it! You already have an API created, with very few lines.

To run, just use the command:

uvicorn run:app --reload

Note: run is the name of the python file you declared your main application and app is the name of the FastAPI object you created.

You must see an output similar to this:

Image by author.

Image by author.

If you open access localhost:8000/ you must get {"hello":"world"} as an output.

Creating the models

Now is time to connect with the database. For this, we use the PyMongo package and just create a MongoClient object:

from pymongo import MongoClient

client = MongoClient()
db = client[database_name]

Note: if your database has a different URI and an authentication, you have to configure it in this step.

FastAPI uses the Pydantic library to check the data and process it. It is a fast and yet easy to use package. You can use it on other projects if you need some data validation and schema.

To create a model in Pydantic library, you have to declare a class that inherits from the BaseModel class. All the fields you want to validate and make part of the model must be declared as attributes.

from pydantic import BaseModel
from bson import ObjectId

class User(BaseModel):
    _id: ObjectId
    name: str
    email: str
    username: str

One of the cool features of Pydantic is that it uses the python typing syntax to check the field type. You can use Optional, Union, and other features of it.

ObjectId

But Pydantic does not have support for the ObjectId class. Every document stored on the database has a field _id, which by default is of type ObjectId.

We have two options here: we can make the _id as another type which is supported by the library; or we can make a custom validator class.

To use with an already created database, we’re going to choose the second option. Basically, we need to implement two methods, get_validators and validate, so Pydantic knows how to deal with it.

The method validate is used to check if the data received is actually valid for this class. So we check it against the ObjectId.is_valid method. In this way, we can accept also a string that is a valid ObjectId. This is useful so we can parse a JSON object received from a HTTP request, for example.

Note: the modify_schema method is to avoid an error when accessing the documentation.

So now we update our model to use this custom object and accept ObjectId types:

We declared here the class User, which inherits from pydantic.BaseModel. This object has four attributes: name, username, and email of string type. And the id field of our new custom type.

MongoDB expects a field with the name _id, but Pydantic does not accept any field that starts with _. Then we create an alias so Pydantic can understand our document.

The inner class Config is used to define some configuration for the model. Here we tell Pydantic that we are using a custom type (by arbitrary_types_allowed) and also a mapping for JSON serialization (by json_encoders).

Endpoints

Now we must change the run.py file so we can use the models we declared on models.py.

We are going to create one endpoint /users which accepts two methods: GET and POST. The first will list all users in database and the latter will insert a new user into the database.

The list_users method gets all the users available on database and send back as a dictionary. FastAPI (and Pydantic) is responsible for translating it to JSON format so the client can understand it.

The create_user method receive an object of User class we declared in our models.py file. We don’t have to worry about the conversion from the JSON body to our model. This is done by FastAPI, since we declared that we expect an argument of type User. Isn’t it great?

Pymongo method insert_one expects a dictionary so it can insert it into database. We use the dict method, passing the argument by_alias as True. This guarantees that the field _id is with the correct name expected by MongoDB.

Testing

And that’s it! Now you can run the program to test it:

uvicorn run:app

Go to localhost:8000/docs and you will see a nice Swagger UI page:

Image by author

Image by author

This page is generated automatically by FastAPI and you can use to test your program.

Conclusion

FastAPI is a nice, fast framework to create an API. If you don’t know it yet, I suggest you start learning it.

In this article, I showed you how you can integrate it with Mongo database in a very nice, simple way.

There is also a nice package called FastAPI Contrib that supports Mongo object as well in some more advanced way.

Follow me on Twitter to know when I write another article.




Continue Learning