The simplest RESTful APIs with Python, Flask, MongoDB, and Docker
Greetings, fellow programmers. This is an article on how to implement a super simple RESTful service using Flask, MongoDB and Docker. If you are reading this article it is probably because you do not want to spend much time on this, and you "probably" will not with this article. Just a few clarifications though. I will try to keep everything as simple as possible but since in programming (and not only there) it is super important to understand what one is doing (not just copy and paste, which is bad 🤬), I will add some small explanation on each step in this tutorial. But enough talking, let's start.
Requirement
- Python 3.6 or higher
- pip
- Docker
- You should know what a RESTful service is and have previous knowledge about the technologies we are going to use.
Table of Content
The simplest RESTful APIs with Python, Flask, MongoDB, and DockerRequirementTable of ContentProblemSolutionBefore startingMongoDB - InstallationFlask - InstallationCode Fully commented code on my Github repo.Code part 1 - Flask basicCode part 2 - Handling RequestsCode part 3 - MongoDB Code part 4 - Web ServiceCode part 5 - NotesDockerRun everythingExternal links and References
Problem
Implement basic methods(GET, POST, PUT, DELETE) for a car-database. The database consists of one collection [Cars: _id, Manufacturer, Model, Color].
Solution
We want a simple and quick solution, and simple means high-level, therefore we need some external packages. We are going to use a single python file, in which we will put all the (simple) logic. Let's start with handling external packages and libraries.
Before starting
The command-line commands are meant for Unix🐧🍎, the logic is the same on Windows but they would need some adjustments.
MongoDB - Installation
There are many ways to install and use MongoDB, if you installed it already, then be sure it is running, otherwise, you can use Docker,
xxxxxxxxxx
$ docker pull mongo
then you could start a MongoDB server instance running something like this:
xxxxxxxxxx
$ docker run --name some-mongo -d mongo:tag -p 27017-27019:27017-27019
then we need PyMongo, to be able to manage MongoDB with Python,
xxxxxxxxxx
$ pip install pymongo
No need to create any collection or entity.
Flask - Installation
What is Flask? let's just say it is the tool we are going to use for creating the service, it is very high-level and indeed it makes easy our job. To install it you can simply run:
xxxxxxxxxx
$ pip install flask
and now, we are good to go programming.
Code
Fully commented code on my Github repo.
Code part 1 - Flask basic
So let's start with the very basic, let's create a python file, called main.py
, (or whatever you want 😉), and add the following.
xxxxxxxxxx
from flask import Flask
app = Flask(__name__)
route('/') .
def index():
return "This is the Service's root"
if __name__ == '__main__':
app.run(debug=True)
This is the "Hello world" for a Flask Service, with the third line app = Flask(__name__)
, we instantiate our flask service. Using @app.route('/')
we locate the root of our service in /
, with the method index
handling this particular path. Now if we run this:
xxxxxxxxxx
$ python main.py
and then if we open our browser at http://127.0.0.1:5000, we can see that we have implemented our very first API, which simply says "This is the Service's root". Pretty easy doesn't it?
Code part 2 - Handling Requests
Now let's create our methods, without MongoDB at first, but don't worry we will add that right away. We will use one single URL, which will handle every method. First, we need another tool from Flask, which will handle our requests:
xxxxxxxxxx
from flask import request
This is the very basic structure of a service implemented with Flask:
xxxxxxxxxx
route('/cars', methods = ['GET', 'POST', 'PUT', 'DELETE']) .
def user():
if request.method == 'GET':
id = request.args.get('id') # get id from parameters
return id
if request.method == 'POST':
data = request.form.to_dict() #multidict data from body
return data
# .....
# PUT and DELETE are the same, only the if-statement changes
Now if we run the program again(or simply save if it is already running) and perform a request (http://localhost:5000/cars/0), using Postman or similar programs, we can see the different responses.
Code part 3 - MongoDB
Let's see how we can implement the POST method then the other will be very similar. First, we need to import MongoClient
by PyMongo and instantiate it using the MongoDB URL (localhost
first, but we will change it later on, when we will put everything on Docker). Finally we need to get references for database(vehicles
) and collections (cars
).
xxxxxxxxxx
from pymongo import MongoClient
client = MongoClient('mongodb://localhost:27017/')
db = client.vehicles
cars = db.cars
For the POST method we simply need to get the request body and store that into our collection using insert_one
like this:
xxxxxxxxxx
if request.method == 'POST':
data = request.form.to_dict() # get multidict data from body
post_id = cars.insert_one(data).inserted_id
return str(post_id)
Here an example using Postman:
Code part 4 - Web Service
Now for the other methods, the implementation will be very similar to the POST method, it is just a matter of choosing the right MongoDB call. A reminder to PyMongo Tutorial and the PyMongo Examples to know more.
The final code is available here. There you can find the complete commented implementation, (I do not copy and paste the code here, because I do not want to fill this article too much). There are 5 URLs:
Method | Url | Description |
---|---|---|
GET | http://localhost:5000/cars | Get all cars |
GET | http://localhost:5000/cars?id={id} | Get car with id={id} |
POST | http://localhost:5000/cars | Post a car |
PUT | http://localhost:5000/cars?id={id} | Modify car with id={id} |
DELETE | http://localhost:5000/cars?id={id} | Delete car with id={id} |
If you run the program, you can test each method(using Postman or other programs), this is an example for a body:
xxxxxxxxxx
{
"Manufacturer" : "Ferrari",
"Model" : "Testarossa",
"Color" : "Yellow"
}
Code part 5 - Notes
Just for clarification, there are many things to take into considerations, for example, parameters checking, content type format, errors of any kind, etc. but since this is just a simple tutorial, we simply skip that shamelessly🤭.
Docker
Before starting we have to change the URL in our MongoClient
in main.py
, changing localhost
, with the name of your MongoDB-docker container (mongodb
in my case):
xxxxxxxxxx
client = MongoClient('mongodb://mongodb:27017/')
And one last important modification, in __main__
, we need to add host='0.0.0.0'
like following: (Here why)
xxxxxxxxxx
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0')
Finally, let's create the Dockerfile
, which is the file from which we will be created the docker image, from which in turn, we will run an instance of itself as Docker container. This is the full code:
xxxxxxxxxx
# Dockerfile
FROM python:3.6 # Base image
# Copy the content of this directory to the container directory /app
COPY . /app
# Setting /app as main Workdir
WORKDIR /app
# Install the requirments, (Flask and pymongo)
RUN pip install -r requirements.txt
# Run the process
ENTRYPOINT ["python"]
CMD ["main.py"]
The last thing we need is the requirements.txt
, on which we simply add our dependencies (i.e. Flask and Pymongo):
xxxxxxxxxx
flask
pymongo
Run everything
So, now that we have three files completed, main.py
, Dockerfile
, and requirements.txt
we can start the service.
First, if not done already, we can run the MongoDB server:
xxxxxxxxxx
$ docker run -d -p 27017-27019:27017-27019 --name mongodb mongo
we can check if everything works for that image running docker exec -it mongodb bash
, and then typing mongo
.
Following, we create the image for the service using this command:
xxxxxxxxxx
$ docker build -t my_rest_service:latest .
and finally, we can run the container:
xxxxxxxxxx
$ docker run --name my_rest_service -d -p 5000:5000 my_rest_service:latest
Now you can test the different methods, and you are good to go. Well Done.
One last note: If you cannot connect to Mongo container from my my_rest_service, be sure the two containers are in the same docker network.
External links and References
- Flask
- Flask example with POST - Stackoverflow
- MongoDB
- Install MongoDB
- MongoDB - docker
- PyMongo
- PyMongo Tutorial
- PyMongo Examples
- What is a workdir - docker?
- Unable to Connect to Flask App On Docker From Host - Stackoverflow
Comments
Post a Comment