Programming

Creating RESTful Web APIs using Flask and Python

A Comprehensive Guide for building Web APIs with Flask

Jimit Dholakia
Towards Data Science
6 min readApr 25, 2020

--

Image by Gerd Altmann from Pixabay

Flask is a widely used micro web framework for creating APIs in Python. It is a simple yet powerful web framework that is designed to get started quickly and easily, with the ability to scale up to complex applications.

From the documentation,

“Micro” does not mean that your whole web application has to fit into a single Python file (although it certainly can), nor does it mean that Flask is lacking in functionality. The “micro” in microframework means Flask aims to keep the core simple but extensible.

Flask Logo
source: Flask’s Documentation

Installation

Install Flask using pip

pip install Flask

Minimal Flask App

from flask import Flask

app = Flask(__name__)

@app.route('/hello/', methods=['GET', 'POST'])
def welcome():
return "Hello World!"

if __name__ == '__main__':
app.run(host='0.0.0.0', port=105)

Save this file as app.py (or any other filename you want) and go to the terminal and type python app.py (i.e. python <filename>.py )

You should see something like this:

* Running on http://0.0.0.0:105/ (Press CTRL+C to quit)

Launch any web browser and go to http://localhost:105/hello/ to see the app in action.

Now, let’s understand the working of the code line-by-line:

from flask import Flask → Import the Flask class

app = Flask(__name__) → Create an instance of the class

@app.route('/hello/', methods=['GET', 'POST']) → We use the route() decorator to tell Flask what URL should trigger the function.
methods specify which HTTP methods are allowed. The default is ['GET']

if __name__ == '__main__'__name__ is a special variable in Python which takes the value of the script name. This line ensures that our Flask app runs only when it is executed in the main file and not when it is imported into some other file

app.run(host='0.0.0.0', port=105) → Run the Flask application

host specifies the server on which we want our flask application to run. The default value for host is localhost or 127.0.0.1

0.0.0.0 means “all IPv4 addresses on the local machine”. This ensures that the server will be reachable from all addresses.
The default port value is 5000 and you can set the parameterportto use the port number of your choice.

Variable Rules

You can add variable sections to a URL by using <variable_name>. The function receives the variable as a keyword argument.

from flask import Flask
app = Flask(__name__)

@app.route('/<int:number>/')
def incrementer(number):
return "Incremented number is " + str(number+1)

@app.route('/<string:name>/')
def hello(name):
return "Hello " + name

app.run()

Run the above code to start the Flask application.
Open the browser and go to http://localhost:5000/Jimit , you will see the output as Hello Jimit and when you go to http://localhost:5000/10 the output will be Incremented number is 11 .

Return JSON Serializable Output

The return value from a function in a Flask app should be JSON serializable. You can use jsonify to make your output JSON serializable. This function wraps json.dumps() to turn the JSON output into a Response object with application/json mime-type.

Example 1:

This example shows how to use jsonify for dictionary objects:

from flask import jsonify

@app.route('/person/')
def hello():
return jsonify({'name':'Jimit',
'address':'India'})

This will send a JSON response like this:

{
"address": "India",
"name": "Jimit"
}

Example 2:

You can also use jsonify to automatically serialize lists and tuples to JSON Response.

from flask import jsonify

@app.route('/numbers/')
def print_list():
return jsonify(list(range(5)))

This will produce output:

[
0,
1,
2,
3,
4
]

Redirection Behaviour

@app.route('/home/')
def home():
return "Home page"

@app.route('/contact')
def contact():
return "Contact page"

In the above example, the URL for the home endpoint has a trailing slash whereas the URL for the contact endpoint is missing the trailing slash.

This results in two different behaviors:

  1. For the home endpoint, if you access the URL without the trailing slash, then Flask redirects you to the URL with the trailing slash.
  2. For the contact endpoint, if you access the URL with the trailing slash, then it will result in the status 404 Not Found.

Return Status Code

You can return the status code along with the Response by specifying the status code as follows:

@app.route('/teapot/')
def teapot():
return "Would you like some tea?", 418

The response to this URL will be Would you like some tea? with 418 as the status code instead of the usual 200 .

Before Request

You can specify a function that should always execute before the request is processed by using app.before_request decorator.

@app.before_request
def before():
print("This is executed BEFORE each request.")

@app.route('/hello/')
def hello():
return "Hello World!"

For this example, the statement This is executed BEFORE each request. will be printed on the server first and then the function for the hello endpoint will be executed. This is particularly useful when you want to log the requests for monitoring purposes.

Accessing Request Data

To access the request data, use the following

from flask import request

You can use the following attributes to fetch the data sent with the request:

request.data → Access incoming request data as a string

request.args → Access the parsed URL parameters. Returns ImmutableMultiDict

request.form → Access the form parameters. Return ImmutableMultiDict

request.values → Returns CombinedMultiDict that combines args and form

request.json → Returns parsed JSON data if mimetype is application/json

request.files → Returns MultiDict object which contains all uploaded files. Each key is the name of the file and the value is the FileStorage object.

request.authorization → Returns an object of Authorization class. It represents an Authorization header sent by the client.

app.run() parameters

app.run() runs the application on the server. There are various parameters that you can use with app.run() in addition to host and port
Some of them are:

debug → If the debug parameter is set to True then the server will automatically reload on code changes and show an interactive debugger in case of unhandled exceptions. The default is False

use_reloader → When use_reloader is set to True , the server will automatically restart when the code changes. Defaults to False

threaded → When threaded is set to True , the process will handle each request in a separate thread. Default is False

ssl_context → SSL Context for the connection. Expects ssl.SSLContext , a tuple in the form (cert_file, pkey_file) , or the string 'adhoc' if the server should automatically create the context. Default is None i.e. SSL is disabled.
This is used when we want to host the Flask application on HTTPS instead of HTTP.

Blueprints

Blueprints allow us to separate various endpoints into subdomains.

home.py

from flask import Blueprint
home_bp = Blueprint('home', __name__)

@home_bp.route('/hello/')
def hello():
return "Hello from Home Page"

contact.py

from flask import Blueprint
contact_bp = Blueprint('contact', __name__)

@contact_bp.route('/hello/')
def hello():
return "Hello from Contact Page"

app.py

from flask import Flask

from home import home_bp
from contact import contact_bp

app = Flask(__name__)

app.register_blueprint(home_bp, url_prefix='/home')
app.register_blueprint(contact_bp, url_prefix='/contact')

app.run()

Note that in both blueprints, the /hello/ route is calling the hello function.

When you go to http://localhost:5000/home/hello , the output will be Hello from Home Page
and when you visit http://localhost:5000/contact/hello , the output will be Hello from Contact Page

Logging

You can use the following methods to log statements in a Flask Application

app.logger.debug('This is a DEBUG message')
app.logger.info('This is an INFO message')
app.logger.warning('This is a WARNING message')
app.logger.error('This is an ERROR message')

--

--