How to create Restful CRUD API with Python Flask, MongoDB, and Docker.

Ishmeet Bindra
11 min readJun 13, 2020

TLDR; We are going to discuss how to use Docker to deploy MongoDB API. Code is available here -Github

This tutorial is going to help you to develop an API interface for MongoDB and will also shed light on isolating MongoDB Server so that it will be accessible only by our API and nothing else (which is an ideal case).

At first, we are going to discuss how to create such API and then we are going to deploy our program to Docker so that our application is truly isolated and environment independent (more about this in later).

We start by an explanation of some basic terminologies relevant to this part-

NoSQL Not Only SQL is an alternative to traditional Relational Databases in which data is stored in strickly defined schemas. In NoSQL, we mostly store data in JSON or JSON-like format. There are many reasons to adopt NoSQL in a project but primary ones are-

  • High Operational Speed
  • Flexibility in Storing Data

Docker — It is a containerizing technology that allows us to containerize our applications so that they are free from environmental drift and are isolated with only a few components exposed for the world to view. A container is similar to a Virtual Machine but is much lighter than an actual VM.

REST — Representational State Transfer is an architectural style design for Application Programming Interface which allows us to get the current state of an application.

CRUD Model — Whenever we are designing an API service, our model must include at least 4 basic types of functionalities — Create, Read, Update, Delete, or CRUD.

In the REST environment, we should use HTTP Methods to provide CRUD operation on any resource. These methods include -

  1. HTTP GET — This method is used to read any resource.
  2. HTTP POST — This method is used to write any resource.
  3. HTTP PUT — This method is used to update any resource.
  4. HTTP DELETE — This method is used to delete any resource.

Please note that you will get to know about different parts of code at different points of time, but at the end, we are creating a single module that can fulfill our requirement of accessing MongoDB via API calls.

Getting Started with Docker and Mongo

In this section, we are going to discuss how to set up a docker environment and how to pull and run a MongoDB application as a container.

Step 1- Setting Up Docker.

Navigate here and download the latest version of Docker.

You can verify the installation by typing the following command in CMD -

docker -v

Step 2- Pulling Mongo DB Image.

For now, we can treat Images as the setup files for an application. An image consists of all the necessary files required for setting up an application or multiple copies of this application in the form of containers.

Fig. 1. Pulling MongoDB Image.

Step 3 Creating a container for MongoDB.

Now that we have our image now we need to run it. For this, we need to create a container. Commands for this are shown below.

Fig. 2. Commands to create and start a MongoDB Container.

So we have our MongoDB container. In under 1 minute 30 seconds of installation of Docker you can have your MongoDB or as a matter of fact any container application up and running. Now note that out of the total time, > 1 minute was used to install the image and creation of the container. Once the image is on our PC and a container is created, we can boot up our application in a matter of seconds (7 seconds in my case).

Let’s discuss the creation command.

docker create -it --name MongoTest -p 5000:27017 mongo
  • docker create to tell we are creating some container
  • -it to tell that it is going to be an interactive container i.e it will communicate with the external environment.
  • --name MongoTest tells that we are going to refer our container with name MongoTest
  • -p 5000:27017 tells that link the MongoDB’s 27017 port with 5000 port of the local machine. MongoDB usually runs on port 27107.
  • mongo name of the image that we want to use to create the image.

Also just to avoid confusion, once you have your container than you always need to run this command to start it

docker start MongoContainerName

To stop a container we use

docker stop MongoContainerName

So we have our MongoDB deployed in container and accessible at port 5000

Fig. 3. Mongo DB deployed at port 5000.

Now in order to properly see what’s available in our Mongo Database, we can use an application called MongoDB Compass

Fig. 4. MongoDB Compass.

As we can see currently we are in Database- IshmeetDB and collection people. Also, it is having one document as of now.

💃Our Database is ready!!!

Creating MongoDB interactor

In this section, we are going to create an API using Flask Server and pymongo that will allow us to interact with previously deployed MongoDB application.

Step 1- Installing and Importing Libraries.

For this project, we require flask and pymongo libraries. Flask will allow us to create a server and pymongo will allow us to interface with MongoDB.

To install these libraries on your environment run the following commands -

Snippet 1. How to install flask and pymongo

Alternatively, you can also refer to the requirements.txt available in the project files and use the following command to install all dependencies in one go -

Snippet 2. How to install all dependencies using requirements.txt

Then create a python file and import the Flask and Pymongo libraries as follows-

Snippet 3. Importing the dependencies into your project.

Step 2- Creating MongoDB interactor.

In this step, we are going to create a module for interacting with MongoDB. Python’s Pymongo library helps us to interact with MongoDB.

Snippet 4 MongoAPI Class.

We begin by creating a simple class and its initialization method. Notice that in this case, we have predefined our client but you can make it more discrete by asking this field from the user.

We are accepting information about Database and Collection from the user and initializing our database collection object through it. We are going to use this collection object throughout our code to read and manipulate data.

Snippet 5 Read Method.

Read Method — This method will allow us to read all of the documents present in our collection. Line number 3 is used to reformat the data. The output of the collection object is of datatype dictionary. We are removing key ‘_id’ as it is containing MongoDB’s internal object ID and is of no use to the user.

Snippet 6. Write Method.

Write Method- This method will allow us to add a new document in MongoDB’s collection. Please note that we are accepting data from the user under the key “Document”. The method used here is insert_one() which will allow us to insert one document at a time. Please note that we are also having another method insert_many() that allows us to insert multiple documents at once and can be implemented with a similar logic.

Snippet 7. Update Method.

Update Method- This method allows us to update any existing documents. For this, we need to accept 2 details from the user. First is the filter on the basis of which we are going to select documents to be updated. Second is DataToBeUpdated. Note that like insert we have used the ‘update_one() method of PyMongo. This can be interchanged with ‘update_many()’ depending upon the requirement. Also, another thing to be noted is that depending upon the availability of data to be updated, we have customized the response.

P.S — Avoid using simple update() as it might give you some unexpected results. I found this to be a very good explanation of the problem you can face.

Snippet 8. Delete Method

Delete Method- This method allows us to delete any existing documents. For this, we are accepting some filtering details form users to extract the documents to be deleted. Note that like update() we also have custom return messages depending on if something was deleted or not.

Now with all that defined, we are going to do a simple test of the module with dummy data. We are going to read the data from our MongoDB database. For that, we are going to use this —

Snippet 10. Main Method

Note that we are only calling read() method in line number 7.

Let’s run the code —

Fig. 5. Running a code to test MongoAPI.py

🎉🎉🎉 It works!

Step 3- Creating a Flask Server.

In order to create the flask server we just need to follow the following steps

  1. Initialize the application. (Line 2)
  2. Define a single entry point so that we could verify that our server is working. (Line 4–8)
  3. Define the ports and IP and start the server. (Line 11)
Snippet 11. Setting up Flask Server

‘@app.route’ is a decorator that defines what endpoint is going to be accepted.

As it is clear that port is equal to 5001 for this project. This is to avoid any conflicts with MongoDB which is accessible on port 5000. Whenever we are going to access this port we are expected to be greeted with {“Status”: “Up”} message as shown below.

Fig. 6. Testing the Flask Server.

Step 4- Defining CRUD HTTP Methods.

Now for real CRUD implementation, we are going to define 4 different HTTP Methods with the help of Flask routes(as described in step 3).

Snippet 12. Read (GET) Method for MongoDB API.
{
"database": "IshmeetDB",
"collection": "people"
}

The code snippet on left shows the implementation of the Read functionality of the CRUD API. We are reading the data when a request is sent using the GET HTTP Method. The JSON data on right shows what data is required by our API for proper functionality. This data will be consumed by ‘Code Snippet 5’ to read everything available in the mentioned MongoDB collection.

Let’s test it out using Postman-

Fig. 7. Testing the GET Method using Postman.

As we can see we got the document that is available in the collection ‘People’. As of now, it consists of 2 fields — First_Name and Age. We are going to see how we can use these 2 fields to add or delete more data.

Snippet 13. Write (POST) Method for MongoDB API.
{
"database": "IshmeetDB",
"collection": "people",
"Document": {
"First_Name": "Jhon",
"Age": 50
}
}

The code snippet on left shows the implementation of the Create functionality of the CRUD API. We are writing the data when a request is sent using the POST HTTP Method. The JSON data on right shows what data is required by our API for proper functionality. We have added a new field of “Document” which consists of the data of the new document which needs to be added. This data will be consumed by ‘Code Snippet 6’ to write new data in the provided collection.

Let’s test it out using Postman-

Fig. 8. Testing the POST Method using Postman.

As we can see the new document got successfully inserted in ‘people’ collection.

Snippet 14. Write (PUT) Method for MongoDB API.
{
"database": "IshmeetDB",
"collection": "people",
"Filter": {
"first_name": "Ishmeet"
},
"DataToBeUpdated": {
"Last_Name": "Bindra",
"Age": 26
}
}

This is how we implement the Update functionality of the CRUD API. We are updating the data when a request is sent using the PUT HTTP Method. The JSON data on right shows what data is required by our API for proper functionality. We have added a new field of “Filter” basis on which we determine which document needs to be updated. Another field that has been introduced is “DataToBeUpdated” which tells which exact data is to be updated. This data will be consumed by ‘Code Snippet 7’ to update existing data in the provided collection.

Let’s test it out using Postman-

Fig. 9. Testing the PUT Method using Postman.

As we can tell, data was successfully updated in the matched document. The field ‘Age’ which was already present in the document got updated whereas the “Last_Name” field which was not there in the document got inserted as a new field.

Snippet 15. Delete (DELETE) Method for MongoDB API.

"database": "IshmeetDB",
"collection": "people",
"Filter": {
"First_Name": "Jhon"
}
}

Finally, this is how we implement the Delete functionality of the CRUD API. We are deleting the data when a request is sent using the DELETE HTTP Method. The JSON data on right shows what data is required by our API for proper functionality. We have added a new field of “Filter” basis on which we determine which document needs to be deleted. This data will be consumed by ‘Code Snippet 8’ to delete existing data in the provided collection.

Let’s test it out using Postman-

Fig. 10. Testing the DELETE Method using Postman.

The document, where First_Name was equal to Jhon, got deleted successfully.

💃Our API is ready!!!

Deploying our code on Docker.

In this section, discuss how to deploy code on docker and how to link 2 docker containers internally. We are going to see how to isolate MongoDB instance so that our API is the only way to access this externally.

Step 1- Defining Dockerfile for our application.

Dockerfile is a configuration file for our program. It defines the basic working environment for our application and also defines how our applications are going to interact with external environments.

Please note that inline 20 we are exposing Port 5001. It is the same port as in our Flask code. This will allow us to communicate to the app in container.

Now since we are having our Dockerfile created we need to create a docker-compose file. A Docker-Compose file allows us to link multiple containers and run them at the same time.

Above is the docker-compose.yml file that we have described in our project directory. Note that in services we have 2 containers. The first one is the Mongo Image that we pulled. The second one is the new container that we are planning to build. Also, note how on line 8 we have defined that our API Container is dependent upon the Mongo Container. This will establish an internal connection between these two containers.

Time to run the containers-

docker-compose run --build

This command will build our containers and run them for us. You can run this command again if you update something in your code but if you just want to bring the container up then just use —

docker-compose run

Please note that this command will only work when the ‘docker-compose.yml’ file is present in the given directory with all the dependent files.

Fig. 11. Testing Docker-Compose command

So that’s it! This is how we create a Restful CRUD API with Python Flask, MongoDB, and Docker. Please post your doubts and views in the comments.

Project Resources — Github

🤖

--

--