In this guide, we will learn how to build a Restful Flask CRUD API. Most beginners prefer to use Flask because it is easy to learn and use as its syntax is more python friendly.
Flask is more flexible, and it doesn’t enforce dependencies. It allows developers to structure their projects the way they want.
Developers are free to use any library and tool provided by Flask for their projects. For building small web applications, the Flask framework is preferable.
Prerequisite
- Basic Python and Flask knowledge
- Little knowledge of Database
- A PC with any Code Editor (VSCode)
- POSTMAN
Installing Flask
We will install Flask by running the code below in our terminal:
pip install flask
After installing Flask, create a Python file, and name it settings.py
. In our settings.py
file, we will import the Flask library.
# importing libraries
from flask import Flask, request, Response, jsonify
We will now create an instance of the Flask app.
# creating an instance of the flask app
app = Flask(__name__)
Configuring SQLAlchemy Database
We will create an SQLAlchemy database with Flask-SQLAlchemy. Flask-SQLAlchemy is a flask extension that provides support for SQLAlchemy. We need to install the library first.
In your terminal, run the code below:
>>> pip install flask-sqlalchemy
We will create a database to store information about movies. In the settings.py file, we will import the flask-sqlalchemy
library and configure it. The name of our database file will be database.db
, we will set sqlalchemy
track modifications to False, so we won’t get any complaint in our terminal.
Let’s create a new file movies.py
and build our database there.
We will first import everything from the settings.py
file and also import JSON.
from settings import *
import json
We will then initialize our database by creating an object of the SQLAlchemy class.
# Initializing our database
db = SQLAlchemy(app)
We will now create a Movie class that will inherit the Model properties of SQLAlchemy class. The table name will be ‘movies’
, and it will contain the following columns: id (primary key), Title, Year, and Genre.
# the class Movie will inherit the db.Model of SQLAlchemy
class Movie(db.Model):
__tablename__ = 'movies' # creating a table name
id = db.Column(db.Integer, primary_key=True) # this is the primary key
title = db.Column(db.String(80), nullable=False)
# nullable is false so the column can't be empty
year = db.Column(db.Integer, nullable=False)
genre = db.Column(db.String(80), nullable=False)
Now let’s define some functions in our Movie class. The first function will help us display our output as JSON.
def json(self):
return {'id': self.id, 'title': self.title,
'year': self.year, 'genre': self.genre}
# this method we are defining will convert our output to json
We will define another function to add a movie to our database.
def add_movie(_title, _year, _genre):
'''function to add movie to database using _title, _year, _genre
as parameters'''
# creating an instance of our Movie constructor
new_movie = Movie(title=_title, year=_year, genre=_genre)
db.session.add(new_movie) # add new movie to database session
db.session.commit() # commit changes to session
We will create another function to get all the movies in our database. Movie.query.all()
will return a list of all the movies in our database. We will loop through the list and convert each movie in the list to JSON with the JSON function we defined earlier. The get_all_movies()
function will return a list containing JSON data.
def get_all_movies():
'''function to get all movies in our database'''
return [Movie.json(movie) for movie in Movie.query.all()]
We will create a function to get a movie in our database with the movie id as a parameter.
def get_movie(_id):
'''function to get movie using the id of the movie as parameter'''
return [Movie.json(Movie.query.filter_by(id=_id).first())]
# Movie.json() coverts our output to the json format defined earlier
# the filter_by method filters the query by the id
# since our id is unique we will only get one result
# the .first() method will get that first value returned
We will create a function to update a movie in our database. After we filter by id, we will update the title, year, and genre of the movie and then commit our changes.
def update_movie(_id, _title, _year, _genre):
'''function to update the details of a movie using the id, title,
year and genre as parameters'''
movie_to_update = Movie.query.filter_by(id=_id).first()
movie_to_update.title = _title
movie_to_update.year = _year
movie_to_update.genre = _genre
db.session.commit()
We will create a function to delete a movie from our database. We will filter by the id and the .delete()
method will delete the movie.
def delete_movie(_id):
'''function to delete a movie from our database using
the id of the movie as a parameter'''
Movie.query.filter_by(id=_id).delete()
# filter movie by id and delete
db.session.commit() # commiting the new change to our database
In your terminal, run the following code:
python
from movies import db
db.create_all()
This will create our database file, which contains our movie table with the columns: id, title, year, and genre. In your directory, you’ll notice a database.db
file.
GET Request
Now that our database has been created, we can now create endpoints for our API.
We will create a file api.py
, where we will define all our API routes. We will import everything from our movies.py
module.
from movies import ***
Now let’s define our route to get all the movies in our database. The endpoint will be ‘/movies’
and the HTTP method will be GET.
# route to get all movies
@app.route('/movies', methods=['GET'])
def get_movies():
'''Function to get all the movies in the database'''
return jsonify({'Movies': Movie.get_all_movies()})
We will also create a route to get movie
by id. We will pass in the movie id to the endpoint, and we will still use the GET method.
# route to get movie by id
@app.route('/movies/<int:id>', methods=['GET'])
def get_movie_by_id(id):
return_value = Movie.get_movie(id)
return jsonify(return_value)
POST REQUEST
Let’s create a route to add a movie to our database.
Our endpoint will still be ‘/movies’
, but the HTTP method will be POST.
# route to add new movie
@app.route('/movies', methods=['POST'])
def add_movie():
'''Function to add new movie to our database'''
request_data = request.get_json() # getting data from client
Movie.add_movie(request_data["title"], request_data["year"],
request_data["genre"])
response = Response("Movie added", 201, mimetype='application/json')
return response
The Response function has three arguments. The first argument is the response body, the second is the status code, which is 201 in this case, and the third is the content-type header that will be sent back to the client.
PUT REQUEST
Let’s create a route to update a movie in our database. We will pass the movie id to our endpoint, and we will use the PUT method.
# route to update movie with PUT method
@app.route('/movies/<int:id>', methods=['PUT'])
def update_movie(id):
'''Function to edit movie in our database using movie id'''
request_data = request.get_json()
Movie.update_movie(id, request_data['title'], request_data['year'], request_data['genre'])
response = Response("Movie Updated", status=200, mimetype='application/json')
return response
DELETE REQUEST
Let’s create a route to delete a movie in our database. We will still pass in the movie
id to our endpoint, but this time we will use the DELETE method.
# route to delete movie using the DELETE method
@app.route('/movies/<int:id>', methods=['DELETE'])
def remove_movie(id):
'''Function to delete movie from our database'''
Movie.delete_movie(id)
response = Response("Movie Deleted", status=200, mimetype='application/json')
return response
if __name__ == "__main__":
app.run(port=1234, debug=True)
Note: When we want to deploy our API, we have to set debug to False in app.run()
.
TESTING WITH POSTMAN
We will use POSTMAN to test our API. First, we will run our api.py file in our terminal
python api.py
We have a warning message in red because we set debug to True. We can only do this during the development stage. But in production, debug has to be set to False.
Let’s test our route by sending a POST request to our API to add a movie to our database
Let’s add another movie to our database.
Let’s view all the movies in our database by using the GET request
Now let’s retrieve the movie with an id of 1.
Let’s update the movie with an id of 1
We can confirm if the movie has been updated by sending a GET request
Now let’s delete the movie with the id of 2
Let’s get all our movies to confirm if the movie with an id of 2 has been deleted.
Conclusion
In this guide, we learned how to build a simple RESTful Flask CRUD API. We also performed some CRUD operations. We can improve on this by adding a validator to verify the requests we receive from our clients. You can check the Github Repo.