DEV Community

Cover image for Flask Rest API -Part:0- Setup & Basic CRUD API
Paurakh Sharma Humagain
Paurakh Sharma Humagain

Posted on • Edited on

Flask Rest API -Part:0- Setup & Basic CRUD API

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?

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
Enter fullscreen mode Exit fullscreen mode

First of all install pipenv
using command

pip install --user pipenv
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

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()
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Now run the app using,

python app.py
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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()
Enter fullscreen mode Exit fullscreen mode

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).

Postman get request response
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()
Enter fullscreen mode Exit fullscreen mode

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 click raw.
  • 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"]
  }
Enter fullscreen mode Exit fullscreen mode

Postman POST request response
POST request response using Postman


In the response you get the id of the recently added movie

{"id": 2}
Enter fullscreen mode Exit fullscreen mode
  • Now again send GET request and see a list of 3 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.

Postman PUT request response

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.
Postman DELETE request response
DELETE request response using Postman

  • Now send a GET request to /movies and see that the movie is already removed from the movies list.

What we learned from this part of the series?

  • Install Flask in a new virtual environment using pipenv
  • 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)

Collapse
 
dilless profile image
Huangbo

Thanks for the tutorial!
There may be some error codes here:

+@app.route('/movies', methods=['POST'])
+def add_movie():
+    movie = request.get_json()
+    movies.append(movie)
+    return {'id': len(movies)}, 200
Enter fullscreen mode Exit fullscreen mode

The add_movie() function return the length of movies as the last id, so the first get request should return id: 3 rather than id: 2 (in the image of post response). And in other function, use index to access movie. So, I think should change return {'id': len(movies), 200 to return {'id': len(movies) - 1, 200 in the code.
Sorry for my poor english.

Collapse
 
paurakhsharma profile image
Paurakh Sharma Humagain

Yes, that's right. I never realized it. Thanks for pointing it out.
Also, your English is good :)

I will update the article shortly.

Collapse
 
jvmazagao profile image
JoΓ£o Victor

I want to point another thing here, the response code should be 201 because we are creating an object, or Am I wrong?

Collapse
 
varuntumbe profile image
Varun Hegde

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

Collapse
 
paurakhsharma profile image
Paurakh Sharma Humagain

Yes sure, just two ways of doing same thing ;)

Collapse
 
varuntumbe profile image
Varun Hegde

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).

Collapse
 
sph73 profile image
SPH73 • Edited

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. :(

Collapse
 
paurakhsharma profile image
Paurakh Sharma Humagain

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.

Collapse
 
beddiafmeriem profile image
BeddiafMeriem

it's maybe because you forgot to specify the index in your put or delete request "localhost/movies/1"

Collapse
 
sph73 profile image
SPH73

Hi, thanks yes I didn't specify an index, so that might be it.

Collapse
 
israelias profile image
Joem Elias Sanez

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.

Collapse
 
lukefirstofhisname profile image
luke

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 -

Collapse
 
purpetrator profile image
purpetrator

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

Collapse
 
lukasmari profile image
Lukas Marivoet

Super tutorial, a really practical walkthrough of working with Flask. Awesome job!

Collapse
 
paurakhsharma profile image
Paurakh Sharma Humagain

I am glad that you liked it πŸ™‚

Collapse
 
corsibu profile image
corsibu

Hi, thanks for the tutorial, I enjoyed going through it. Do you think you could add another post about testing?

Collapse
 
paurakhsharma profile image
Paurakh Sharma Humagain

I am glad that you liked it.
I am planning to write about exception handling next and then testing :)

Collapse
 
just012 profile image
Just Basumatary

Thanks for the tutorial mate. It really helped me in understanding the working of Flask API.

Collapse
 
drsimplegraffiti profile image
Abayomi Ogunnusi

Thanks for the tutorial