Part 0: Setup & Basic CRUD API
Howdy! Welcome to the Flask Rest API - Zero to Yoda, tutorial series. We will go through building a Movie database where a user can (Add, Edit, Update & delete) Genre
, Movie
, and Casts
. First of all, we will start with a basic APIs structure with just Flask
and then learn about integrating MongoDB
with the application, finally, we will learn about structuring our API following the best practices with the minimal setup using Flask-RESTful
. And then we will continue with Authentication
and Authorization
, testing and deploying flask application.
What we are going to learn in this series?
- Flask - For our web server.
- flask-restful - For building cool Rest-APIs.
- Pipenv For managing python virtual environments.
- mongoengine - For managing our database.
- flask-marshmallow - For serializing user requests.
- Postman - For testing our APIs
- Flask-Bcrypt For hashing user password.
- Flask-JWT-Extended For creating tokens for authorization and authentication.
Why flask?
- Easy to get started π
- Great for building Rest APIs and microservices.
- Used by big companies like Netflix, Reddit, Lyft, Et cetera.
- Great for building APIS for machine learning applications.
- Force is strong with this one π
Who is this series for?
- Beginners with basic Python knowledge who wants to build cool apps.
- Experienced flask developers who have been working with flask
SSR
(Server Side Rendering).
So, let's get started.
First of all, create a new directory and browse to the newly created directory, I'm gonna call it movie-bag
.
mkdir movie-bag
cd movie-bag
First of all install pipenv
using command
pip install --user pipenv
Pipenv
is used to create a virtual environment
which isolates the python packages you used in this project from other system python packages. So, that you can have a different version of same python packages for different projects.
Now, let's install flask
using pipenv
pipenv install flask
This will create a new virtual environment and install flask. This command will create two files Pipfile
and Pipfile.lock
.
#~ movie-bag/Pipfile
[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true
[dev-packages]
[packages]
flask = "*"
[requires]
python_version = "3.7"
Pipfile contains the packages that are required for your application. As you can see flask
is added to [packages]
list. This means when someone downloads your code and runs pipenv install
, flask
gets installed in their system. Great, right?
If you are familiar with requirements.txt
, think Pipfile
as the requirements.txt
on steroids.
Flask is so simple that you can create an API using a single file. (But you don't have to π )
Create a new file called app.py
where we are gonna write our Flask Hello World API. Write the following code in app.py
#~movie-bag/app.py
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return {'hello': 'world'}
app.run()
Let's understand what we just wrote. First of all, we imported the Flask
class from flask
package.
Then we define a root endpoint with @app.route('/')
, @app.route()
is called a decorator
which basically takes function hello()
extends it's behavior so that it is invoked when /
endpoint is requested. And hello()
returns {'hello': 'world'}
, finally Flask
server is started with app.run()
Wanna learn more about decorators? Read this great article
There you go, you have made yourself your very first Flask API (Pat on your back).
To run the app, first, enable the virtual environment that you created earlier while installing Flask
with
pipenv shell
Now run the app using,
python app.py
The output looks like this:
* Serving Flask app "app" (lazy loading)
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: off
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
As you can see the app is running on http://127.0.0.1:5000/
. Type the URL in your browser of choice and see the JSON
response from the server.
Note: Alias for 127.0.0.1 is localhost, So you can access your API at http:localhost:5000 aswell
Now let's update our app.py
to have more fun π
#~/movie-bag/app.py
-from flask import Flask
+from flask import Flask, jsonify
app = Flask(__name__)
+movies = [
+ {
+ "name": "The Shawshank Redemption",
+ "casts": ["Tim Robbins", "Morgan Freeman", "Bob Gunton", "William Sadler"],
+ "genres": ["Drama"]
+ },
+ {
+ "name": "The Godfather ",
+ "casts": ["Marlon Brando", "Al Pacino", "James Caan", "Diane Keaton"],
+ "genres": ["Crime", "Drama"]
+ }
+]
+
-@app.route('/')
+@app.route('/movies')
def hello():
- return {'hello': 'world'}
+ return jsonify(movies)
app.run()
Note: In the code snippet above, -
(red
) represents the part of the previous code that was removed and +
(green
) represents the code that replaced it. So, if you are coding along with me. Only copy the green
codes excluding +
sign.
Here we imported jsonify
from flask
which is used to convert our movies
list into proper JSON
value.
Notice we also renamed our API endpoint from /
to /movies
.
So, now our API should be accessable at http://localhost:5000/movies
To see the changes, restart your Flask
server.
To work with our APIs, we are going to use Postman
. Postman is used for testing the APIs with different HTTP methods. Such as sending data to our web server with POST
request, updating the data in our server with PUT
request, getting the data from the server with GET
and deleting them with DELETE
request.
Learn more about REST API HTTP methods here.
Install Postman to test your API endpoint easily.
After installing Postman
, open a new tab and send the GET
request to your server (http://localhost:5000).
GET request response using Postman
Ok now we are ready to add new API endpoints for CRUD
(Create, Update, Retrieve & Delete)
Add the following code in app.py
before app.run()
#~movie-bag/app.py
-from flask import Flask, jsonify
+from flask import Flask, jsonify, request
app = Flask(__name__)
@@ -19,5 +19,21 @@ movies = [
def hello():
return jsonify(movies)
+@app.route('/movies', methods=['POST'])
+def add_movie():
+ movie = request.get_json()
+ movies.append(movie)
+ return {'id': len(movies)}, 200
+
+@app.route('/movies/<int:index>', methods=['PUT'])
+def update_movie(index):
+ movie = request.get_json()
+ movies[index] = movie
+ return jsonify(movies[index]), 200
+
+@app.route('/movies/<int:index>', methods=['DELETE'])
+def delete_movie(index):
+ movies.pop(index)
+ return 'None', 200
app.run()
As you can see @app.route()
can take one more argument in addition to the API endpoint. Which is methods
for API endpoint.
What we have just added are:
1) @app.route('/movies', methods=['POST'])
endpoint for adding a new movie to our movies
list. This endpoint accepts the POST
request. With POST
request you can send a new movie for the list.
Use postman to send a movie via POST request
- Select
POST
from the dropdown - Click on the
Body
tab and then clickraw
. - Select
JSON
from the drop down (indicating we are sending the data to our server in JSON format.) - Enter the following movie details and hit
SEND
{
"name": "The Dark Knight",
"casts": ["Christian Bale", "Heath Ledger", "Aaron Eckhart", "Michael Caine"],
"genres": ["Action", "Crime", "Drama"]
}
POST request response using Postman
In the response you get the id of the recently added movie
{"id": 2}
- Now again send
GET
request and see a list of3
movies is responsed by the server π
2) @app.route('/movies/<int:index>', methods=['PUT'])
endpoint for editing the movie which is already existing on the list based on it's index
as suggested by <int:index>
. Similarly for PUT
request also you have to include the JSON
body for the movie you want to update.
PUT request response using Postman
- Now send a
GET
request to see the movie you updated actually getting updated on the list of movies.
3) @app.route('/movies/<int:index>', methods=['DELETE'])
API endpoint for deleting the movie from the given index of movies list.
DELETE request response using Postman
- Now send a
GET
request to/movies
and see that the movie is already removed from themovies
list.
What we learned from this part of the series?
- Install
Flask
in a new virtual environment usingpipenv
- Create a simple hello world flask application
- Create API endpoints with
CRUD
functionality.
That's it for this part of the series y'all.
You can find the code for this part here.
In this part, we only learned how to store movies in a python list but in the next part of the series, we are going to learn how we can use Mongoengine
to store our movies in the real MongoDB
database.
Until then happy coding π
Top comments (25)
Thanks for the tutorial!
There may be some error codes here:
The
add_movie()
function return the length of movies as the last id, so the first get request should returnid: 3
rather thanid: 2
(in the image of post response). And in other function, use index to access movie. So, I think should changereturn {'id': len(movies), 200
toreturn {'id': len(movies) - 1, 200
in the code.Sorry for my poor english.
Yes, that's right. I never realized it. Thanks for pointing it out.
Also, your English is good :)
I will update the article shortly.
I want to point another thing here, the response code should be 201 because we are creating an object, or Am I wrong?
I am having trouble installing pipenv. i added path variable also and now i cant run pipenv shell command. Can i do this using venv package management ?
(pls correct me if i am wrong , newbie here).
Thanks in advance
Yes sure, just two ways of doing same thing ;)
And one last thing when i import db from .db in model.py i get this error
-Attempted relative import beyond top level package .(its given by pylint in vscode).
Hi! Is there any chance someone can see what I am doing wrong? I can do get and post requests but put and delete give a 405 error. I have uploaded a screenshot. TIA!
Edit:
Don't know why the screenshot isn't showing and I can't even paste into this box. :(
Hey, I am not sure why you are having this problem.
You should be able to upload the screenshot using
upload image
icon.If for some reason you cannot. You can upload your screenshot somewhere and paste the link here.
Or maybe your project GitHub URL.
it's maybe because you forgot to specify the index in your put or delete request "localhost/movies/1"
Hi, thanks yes I didn't specify an index, so that might be it.
I just stumbled upon this three and a half years later. Alas, my comment and me meet again! I owe this seven part series my future. Passing by and paying dues? It deserves a Google review. This tutorial was foundational.
I basically copied the code from the tutorial.
when I try to POST using Postman, I get the following error
TypeError: TopLevelDocumentMetaclass object argument after ** must be a mapping, not NoneType
127.0.0.1 - - [17/Oct/2020 16:26:32] "POST /movies HTTP/1.1" 500 -
Absolutely love this tutorial series, thank you SO much!
One quick little typo I noticed that may throw off some beginners - you call the GET request on localhost:5000/ instead of localhost:5000/movies in postman
Super tutorial, a really practical walkthrough of working with Flask. Awesome job!
I am glad that you liked it π
Hi, thanks for the tutorial, I enjoyed going through it. Do you think you could add another post about testing?
I am glad that you liked it.
I am planning to write about exception handling next and then testing :)
Thanks for the tutorial mate. It really helped me in understanding the working of Flask API.
Thanks for the tutorial