DEPLOYING REST-API BASED FLASK APP ON HEROKU — Part 1

Ashiq KS
11 min readOct 25, 2018

--

This is an introductory tutorial on creating a REST API with python’s Flask micro web framework and deploying it to Heroku cloud platform for production.

This tutorial and next part show creating a flask REST API application along with a sqlite database to store the details of movies. This database contains 5 fields/columns to enter in the details of the movies. Moreover, with the GET, POST, PUT and DELETE methods of HTTP, using the flask REST API, we will see how to interact with the web and database.

In the second part, the application will be tested and deployed on Heroku’s cloud platform. And in the subsequent sections we will dive deep into creating a simple web app with the above mentioned frameworks along with a SQLite database. All the codes are available on my Github repo. This post is divided into 2 sections: Developing the application and Deploying the application on the cloud.

Before getting started let’s review what REST API, Flask and Heroku are.

What exactly is a REST-API?

Before looking into REST, let’s see what an API is.

An API is an interface through which one program or web site talks to another. They are used to share data and services, and they come in many different formats and types.

A RESTful API is one of the many possible ways that programs, servers, and websites can share data and services. REST (Representational State Transfer) describes the general rules for how the data and services are represented through the API so that other programs will be able to correctly request and receive the data and services that an API makes available.

REST uses HTTP (the protocol used by a browser to get web pages from a server) to represent “resources.” The most familiar resource for most people is a web page, but resources can be anything you can describe over the web. In addition to pages, you can use this to share data such as package delivery information, time information, purchasing information…the list is as long as you can imagine. The services that provide the REST API can act on these resources in whatever way makes sense. For example, a service could provide the ability to get information about them, create information about them or create the actual resource, delete them, modify them, to name the most common actions one can take on a web resource.

Some of the common HTTP methods are listed below:

  1. GET: is used to request data from a specified resource.

2. POST: is used to send data to a server to create a resource.

3. PUT: is used to send data to a server to create/update a resource.

4. DELETE: is used to delete data from a specified resource.

So, with the ability to create, read, update, and delete anything you can describe over the web, you can see how powerful they can be.

FLASK — Python’s micro web framework

Flask is a micro web framework written in Python. It allows you to build web apps and websites quite rapidly and easily, it’s really good and light. Flask is also easy to get started with as a beginner because there is little boilerplate code for getting a simple app up and running.

For example, here is a valid “Hello, world!” web application with Flask:

from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello, World!'
if __name__ == '__main__':
app.run()

The above code shows “Hello, World!” on localhost port 5000 in a web browser when the Flask library is installed and the program is executed. It is that easy to get started off with Flask.

In this post, we need to use the REST extension of flask, flask_restful, to implement the REST API.

Heroku - For app deployment

Heroku is a cloud platform that enables developers to build, run, and operate applications entirely in the. It is a Platform-as-a-Service (PaaS) supporting several programming languages that are used as a web application deployment model. Heroku, one of the first cloud platforms, has been in development since June 2007, when it supported only the Ruby programming language, but now supports Java, Node.js, Scala, Clojure, Python, PHP, and Go. For this reason, Heroku is said to be a polyglot platform as it lets the developer build, run and scale applications in a similar manner across all the languages.

Developing the Application

To start off, we need to install the necessary packages:

  1. flask
  2. flask_restful
  3. flask_sqlalchemy

We can use python’s pip package installer to install the packages.

Let’s start off with loading two files of python programs, named app.py and base.py .

#app.py#Import necessary packages
from flask import Flask
from flask_restful import Resource, reqparse, Api
#Instantiate a flask object
app = Flask(__name__)
#Instantiate Api object
api = Api(app)
#Setting the location for the sqlite database
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///base.db'
#Adding the configurations for the database
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['PROPAGATE_EXCEPTIONS'] = True
#Import necessary classes from base.py
from base import Movies, db
#Link the app object to the Movies database
db.init_app(app)
app.app_context().push()
#Create the databases
db.create_all()
#Creating a class to create get, post, put & delete methods
class Movies_List(Resource):

#Instantiating a parser object to hold data from message payload
parser = reqparse.RequestParser()
parser.add_argument('director', type=str, required=False, help='Director of the movie')
parser.add_argument('genre', type=str, required=False, help='Genre of the movie')
parser.add_argument('collection', type=int, required=True, help='Gross collection of the movie')

#Creating the get method
def get(self, movie):
item = Movies.find_by_title(movie)
if item:
return item.json()
return {'Message': 'Movie is not found'}

#Creating the post method
def post(self, movie):
if Movies.find_by_title(movie):
return {' Message': 'Movie with the title {} already exists'.format(movie)}

args = Movies_List.parser.parse_args()
item = Movies(movie, args['director'], args['genre'], args['collection'])

item.save_to()
return item.json()

#Creating the put method
def put(self, movie):
args = Movies_List.parser.parse_args()
item = Movies.find_by_title(movie)
if item:
item.collection = args['collection']
item.save_to()
return {'Movie': item.json()}
item = Movies(movie, args['director'], args['genre'], args['collection'])
item.save_to()
return item.json()
#Creating the delete method
def delete(self, movie):
item = Movies.find_by_title(movie)
if item:
item.delete_()
return {'Message': '{} has been deleted from records'.format(movie)}
return {'Message': '{} is already not on the list'.format()}

#Creating a class to get all the movies from the database.
class All_Movies(Resource):
#Defining the get method
def get(self):
return {'Movies': list(map(lambda x: x.json(), Movies.query.all()))}
#Adding the URIs to the api
api.add_resource(All_Movies, '/')
api.add_resource(Movies_List, '/<string:movie>')
if __name__=='__main__':
#Run the applications
app.run()
#base.py#Importing sqlalchemy
from flask_sqlalchemy import SQLAlchemy
#Instantiating sqlalchemy object
db = SQLAlchemy()
#Creating database class
class Movies(db.Model):

#Creating field/columns of the database as class variables
id = db.Column(db.Integer, primary_key=True)

title = db.Column(db.String(30), unique=True, nullable=False)

director = db.Column(db.String(30), unique=False,nullable=False)
genre = db.Column(db.String(30), unique=False, nullable=False) collection = db.Column(db.Integer, unique=False, nullable=False) def __init__(self, title, director, genre, collection):
self.title = title
self.director = director
self.genre = genre
self.collection = collection

#Method to show data as dictionary object
def json(self):
return {'Title': self.title, 'Director': self.director, 'Genre': self.genre, 'Collection': self.collection}

#Method to find the query movie is existing or not
@classmethod
def find_by_title(cls, title):
return cls.query.filter_by(title=title).first()
#Method to save data to database
def save_to(self):
db.session.add(self)
db.session.commit()
#Method to delete data from database
def delete_(self):
db.session.delete(self)
db.session.commit()

Let’s begin from base.py. In this file, we import flask extension of SQLAlchemy, flask_sqlalchemy, from it we import SQLAlchemy class and initiate an object of later as ‘db’.

#Importing sqlalchemy
from flask_sqlalchemy import SQLAlchemy
#Instantiating sqlalchemy object
db = SQLAlchemy()

Then, a class model is created to represent a single database using the SQLAlchemy.Model() class as follows:

class Movies(db.Model):

In this database, there are 5 fields/columns named, ‘id’, ‘title’, ‘director’, genre’ and the total ‘collection’ of the movie. We will pass the values for these fields in the constructor of the class while instantiating.

db.Column() is used to create a field/column in the database and we specify the type of field/column. Common types are Integer, String and Text datatypes. The String datatype takes an argument to state the length of the string object. The id is a unique column to number the rows of the database. It is made unique by specifying the unique=True parameter in the db.Column. nullable parameter determines whether the data for that column can be null or not.

We will create a helper function to format the data as a dictionary object using the following method:

def json(self):        
return {'Title': self.title, 'Director': self.director, 'Genre': self.genre, 'Collection': self.collection}

In addition to the json method, another helper function is implemented to check a given is existing in the database or not. This method uses the query method to Model class to query into the database and then filter the movie by title and returns the first object found.

@classmethod    
def find_by_title(cls, title):
return cls.query.filter_by(title=title).first()

We want to save new movies and its details and sometimes we may want to delete a particular movie from the database. For that, two functions are created as follows:

def save_to(self):        
db.session.add(self)
db.session.commit()
def delete_(self):
db.session.delete(self)
db.session.commit()

db.session.add() method adds a movie and its details to a database and it is saved by committing db.session.commit().

db.session.delete() delete an entry from the database and saves the commit by db.session.commit()

Now let’s go back to the main program, app.py.

We start off by importing the necessary packages as follows.

from flask import Flask
from flask_restful import Resource, reqparse, Api

Then we need to instantiate Flask and Api objects as app and api.

#Instantiate a flask object 
app = Flask(__name__)
#Instantiate Api object
api = Api(app)

Now we need to configure the database in order to run it with the app. The location of the database is set to the SQLALCHEMY_DATABASE_URI config variable of the app object.

#Setting the location for the sqlite database
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///base.db'
#Adding the configurations for the database
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['PROPAGATE_EXCEPTIONS'] = True

After this, we import the db instance from base.py. Why this is imported now is to avoid circular import and the database is linked to the app.

#Import necessary classes from base.py
from base import Movies, db
#Link the app object to the Movies database
db.init_app(app)
app.app_context().push()
#Create the databases
db.create_all()

Later on, we create a class Movies_List to have the GET, POST, PUT and DELETE methods.

The reqparse.RequestParser() object parses the data inserted in the message payload. The data parsed through this are ‘director’, ‘genre’ and ‘collection’. The movie parameter is specified in the URI, so it gives a lot more freedom and we will see later how to do this.

The get method gets the data from the database. We can get one single data or a whole bunch of data by specifying in the respective class. In the first class Movies_List, we retrieve only a single movie data. All the classes for the HTTP methods inherit from the Resource class from the flask_restful package.

def get(self, movie):        
item = Movies.find_by_title(movie)
if item:
return item.json()
return {'Message': 'Movie is not found'}

The get method takes in a parameter, named ‘movie’ and checks if the data for the movie is already on the database using the find_by_title method from base.py. If yes, then the data is retrieved, if not, then an error message is sent instead.

The next method is post method which posts data to the database.

def post(self, movie):        
if Movies.find_by_title(movie):
return {' Message': 'Movie with the title {} already exists'.format(movie)}

args = Movies_List.parser.parse_args()
item = Movies(movie, args['director'], args['genre'], args['collection'])

item.save_to()
return item.json()

This method, too, takes in a parameter, ‘movie’. First of all, it takes in the data we sent in the message payload using the parser object we created earlier and checks the data for the movie already exists or not. If exists, then we return only the message saying we already have the data for the movie passed in as the argument because we have another method, put, for updating an existing movie data.

If the movie is not present, then a Movies class object is instantiated with the necessary arguments and saved to the database using the helper function from base.py.

As mentioned above we have a method to update the existing data in the database, it is the put method.

def put(self, movie):        
args = Movies_List.parser.parse_args()
item = Movies.find_by_title(movie)
if item:
item.collection = args['collection']
item.save_to()
return {'Movie': item.json()}
item = Movies(movie, args['director'], args['genre'], args['collection'])
item.save_to()
return item.json()

In the put method, we let the user update only the collection field. As in the post method, it checks if a movie is in the database or not. If yes, it allows changing only the collection field. If the movie is not present, then we create new movie data as post method.

The last method is the delete method, to delete a single entry from the database.

def delete(self, movie):        
item = Movies.find_by_title(movie)
if item:
item.delete_()
return {'Message': '{} has been deleted from records'.format(movie)}
return {'Message': '{} is already not on the list'.format()}

We first check a movie is present in the database, the movie that is passed in as the argument. If present, then with the delete_() function from base.py we delete the movie entry. If the movie is not present, then a message is returned saying the passed in the movie was not in the database.

Our next class is All_Movies which has only one method, the get method to get all the movies in the database.

def get(self):        
return {'Movies': list(map(lambda x: x.json(), Movies.query.all()))}

This method queries all the movies in the database using the lambda function and returns all.

Next section is adding the URIs to send requests to the web server.

api.add_resource(All_Movies, '/')
api.add_resource(Movies_List, '/<string:movie>')

The add_resource method takes in two parameters, the resource class and the URI. In the first line, the class is the All_Movies class and the ‘/’. For eg, how this works is, since All_Movies class has only one method, get, and using our localhost — http://127.0.0.1:5000/, after running the application if we go to this site using our web browser we will get all the movies details from the database. Note that ‘/’ is appended after the port number 5000.

To make the concept concrete, take the second line, it takes in the Movies_List and ‘/<string:movie>’ parameters. The string in the code represents the data type we will mention in the URI will be a string type. The movie is a placeholder to hold the movie we mention. For eg, we want to insert in a movie data ‘Avatar’, we need to go to ‘http://127.0.0.1:5000/Avatar’ along with posting the necessary data and we will see it in the next section. The URL can be any address of where our application is running, in our testing case it will be our localhost.

In the next post, we will see how to test our application using the Postman application. Postman is an application for interacting with HTTP APIs. It presents one with a friendly GUI for constructing requests and reading responses.

Moreover, we will see how to deploy our application in a cloud service, Heroku, and test it using the Postman.

Please be sure to check Part 2 of this tutorial.

Please comment below to let me know your thoughts and suggestions.

--

--