Flask API using Flask RestFul

Binary Tree Problems books

Get FREE domain for 1st year and build your brand new site

Flask is python based web framework which lets developers design complex web applications. It is small and easy to use and is one of the most popular web frameworks with lots of users worldwide and being used in many large scale industries and startups.

We will be developing a flask API using flask restful in which we will be performing all the basic CRUD operations.
The basic CRUD operations include create,read , update and delete. We will be interacting with a mysql database to store our data and creating a route with the various HTTP methods which will be used to add data , update , delete and display the data.

To follow along these are the components we will be using

  • Flask
  • SqlAlchemy
  • Flask-Restful

Directory Structure

The directory structure for the Api will be as follows
Selection_103

The directories present are

  • model : This contains all the database models which we will require for our API
  • route : This contains all the route definitions of the API

The app.py is the main file which will run to start up the server , the api routes and database models are imported and initialised before the server is run.

Coding the api

Initial App

In this section let us begin by initialising the app and importing the neccessary packages required .

from flask import Flask
from flask_restful import Api

app = Flask(__name__)
api = Api()

app.config["SECRET_KEY"] = "restapi"
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///site.db"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] =  False

@app.before_first_request
def create_tables():
    db.create_all()
if __name__=="__main__":
    from database import db
    db.init_app(app)
    api.init_app(app)
    app.run(debug=True)

First we import the packages that we require and create the objects . We create the flask object and store it in app ,we also create a sqlalchemy object , sqlalchemy is a library that is used as an ORM(Object Relational Mapper) tool that allows us to define database tables as python classes and facilitates the communication between the program and database.
The database URI is defined in the app.config["SQLALCHEMY_DATABASE_URI"] and the db.create_all() method is used to create the database tables and it is triggered before the first request coming to the server.
The Api Object is imported from flask restful which will help us define the objects in our api routes which are written in the route directory and discussed below.

Finally the objects are initialised before the app is run , the default port a flask app runs is 5000

Selection_105

Database Models

All this comes under the model directory where we have a init.py file present and the models are defined in a book.py file . We will create a database to store book details . The details to store will be

  • book id - primary key of the books
  • name - name of the book , has to be unique
  • price - price of book
  • publication - company publishing the book

The database schema is represented using a python class in which we take the base class as db.Model which is stored in the sqlalchemy object that we have created.
To ease the database operations we add few methods to the class which are explained below.

from database import db
class BookModel(db.Model):
    __tablename__="store"
    id = db.Column(db.Integer,primary_key=True)
    name = db.Column(db.String(20),unique=True,nullable=False)
    price = db.Column(db.Integer,nullable=False)
    publication = db.Column(db.String(20),nullable=False)


    def __init__(self,name,price,publication):
        self.name = name
        self.price = price
        self.publication = publication


    @classmethod
    def find_by_name(cls,name):
        return cls.query.filter_by(name=name).first()
    
    def add_to_db(self):
        db.session.add(self)
        db.session.commit()
    
    def delete_from_db(self):
        db.session.delete(self)
        db.session.commit()

The database schema is defined using the BotModel Class , which has three methods

  • find_by_name : searches for a book name provided by user and returns that row from database if such a book present. It is a class method.
  • add_to_db : adds and saves the data in the object to the database.
  • delete_from_db : removes the data in the object from database.

Routes

All the files come under the route directory where we have a init.py file initially and the routes are defined in the books.py file.

We start by importing the necessary packages and modules.

from flask_restful import Resource
from model.book import BookModel
from flask import request,jsonify,make_response

Four types of requests are defined here

  • Post - Add data to database
  • Get - Display data from database
  • PUT - Update particular data of the database
  • Delete - Delete an entry from database

Flask Restful allows us to define a class which inherits from the base class Resource which is imported from flask restful. It allows us to define multiple HTTP methods by defining methods of our class.

The BookModel is the class defined in the database models file which is explained above and imported here.

POST

class BookRoute(Resource):
    def post(self):
        data = request.get_json()
        name = data["name"]
        price = data["price"]
        publication = data["publication"]

        obj = BookModel.find_by_name(name)
        if obj is not None:
            return make_response(jsonify({
                "Msg": "Book Exists",
                "Status": 404
            }),404)
        bookObj = BookModel(name=name,price=price,publication=publication)

        bookObj.add_to_db()

        return make_response(jsonify({
                "Msg": "Book Added",
                "Status": 200
            }),200)

We create the class BotRoute under which we define the HTTP methods . The post method takes in the data which is retrieved through the request module.

The data contains the entry for a new book ,since the book names have to be unique we first check whether a book with the same name exists or not using the find_by_name . If we get back an object it means a book with same name exists and we return a response stating that this book exists.

When the book does not exist , we create an object of the Book using the BookModel class which has been imported from the database file and using the method add_to_db we add the entry to database and return a response.

GET

def get(self):
        data = request.get_json()
        name = data["name"]

        obj = BookModel.find_by_name(name)

        if obj is not None:
            return make_response(jsonify({
                "Name": obj.name,
                "Price": obj.price,
                "Publication": obj.publication
            }),200)

        return make_response(jsonify({
                "Msg": "Book Does not exist",
                "Status": 404
            }),404)

For the get method we only need the name of book and display its content . We take the name of the book from the user and check whether the book exists or not using the find_by_name of the BookModel class , if present we return the details of the book as a response.

If the book is not present we return a response stating that such a book is not present.

DELETE

def delete(self):
        data = request.get_json()
        name = data["name"]

        obj = BookModel.find_by_name(name)

        if obj is None:
            return make_response(jsonify({
                "Msg": "Book Does not exist",
                "Status": 404
            }),404)
        
        obj.delete_from_db()

        return make_response(jsonify({
            "Msg": "Book Deleted",
            "Status": 202
        }),202)

The delete method is similar to the get method where we only take in the book name and check whether it exists or not.

If a book with given name is present delete the book using the delete_from_db method and return a response stating that the book has been deleted and if the book is not present return a response stating that the book with this name is not present .

PUT

def put(self):
        data = request.get_json()
        name = data["name"]
        price = data.get("price")
        publication = data.get("publication")

        obj = BookModel.find_by_name(name)

        if obj is None:
            return make_response(jsonify({
                "Msg": "Book Does not exist",
                "Status": 404
            }),404)
        
        if price:
            obj.price = price
        if publication:
            obj.publication = publication
        
        obj.add_to_db()

        return make_response(jsonify({
            "Msg": "Book Details Updated",
            "Status": 200
        }),200)

The put method is used to update the values . Here a user provides the book name and might want to update the price , publication or both. hence we use the request.get method which defaults to None if either one of price or publication is not provided by the user.

We check if the book name provided by the user exists or not and then update the values of the object based on the parameters the user has provided.

Once we update we save the updated values to the database and return a response of successful update.

Finally we are ready to start working with our api , import it into the main app.py and then run the app.

The final script of app.py looks like this , in line 16 we have defined the route using the add_resource method which comes under flask restful.

from flask import Flask
from flask_restful import Api
from route.books import BookRoute


app = Flask(__name__)
api = Api()

app.config["SECRET_KEY"] = "restapi"
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///site.db"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] =  False

@app.before_first_request
def create_tables():
    db.create_all()
    
api.add_resource(BookRoute,"/books")

if __name__=="__main__":
    from database import db
    db.init_app(app)
    api.init_app(app)
    app.run(debug=True)

Now we can go ahead and run our app and test out our routes

Selection_113

Adding a Book using the post route , we add the Sherlock Holmes book with price 10 and publication penguin
Selection_114
Book has been added successfully , now let us view the book using a get request , only book name is required in this case

Selection_115

Let us go ahead update the price of the same book using a put request
Selection_118

Now if we use a Get request to view details of the book again
Selection_119

The price has been update to 45 from 10.

Now let us go ahead and delete the book entry
Selection_121
If we try to view the book now we get a message that the book does not exist
Selection_122

This way we can define multiple routes and associate different HTTP methods to the routes with ease using flask restful. It allows us to modularise the code and separate the different functionalities.Flask Restful allows us to develop the entire backend of applications which can be used in production level also.