Open-Source Internship opportunity by OpenGenus for programmers. Apply now.
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
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
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
Adding a Book using the post route , we add the Sherlock Holmes book with price 10 and publication penguin
Book has been added successfully , now let us view the book using a get request , only book name is required in this case
Let us go ahead update the price of the same book using a put request
Now if we use a Get request to view details of the book again
The price has been update to 45 from 10.
Now let us go ahead and delete the book entry
If we try to view the book now we get a message that the book does not exist
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.