Building a RESTful Flask CRUD API


In this guide, we will learn how to build a Restful CRUD API with Flask. 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 project. 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.

flask

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

flask

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 in 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

RESTful CRUD API with Flask

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

RESTful CRUD API with Flask

Let’s get all our movies to confirm if the movie with an id of 2 has been deleted.

RESTful CRUD API with Flask

CONCLUSION
In this guide, we learned how to build a simple RESTful API with Flask. 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.


Share on social media

//