Falcon: A High Performance, Lightweight Web Framework

0
12087

High preformance computing

Falcon is a lightweight, high performance framework for building cloud APIs. If your aim is to serve requests as quickly as possible by putting in some extra effort during the development stage, then you should give Falcon a try.

To build Web applications, developers generally tend to pick a language like PHP. While Python is closely associated with scientific computing, it offers an array of choices when it comes to building Web scale applications. The world of Python is loaded with Web frameworks (some of which are listed in Table 1).

Table 1: Web frameworks in Python
Screenshot from 2016-10-03 18-02-11

As can be seen from Table 1, each Web framework has its own set of features and target scenarios. If you are interested in a comparative analysis of their performance, visit http://klen.github.io/py-frameworks-bench/.  Post analysis, Falcon will emerge as one among the top ranked frameworks.

Falcon design goals

Falcon official documentation lists the following three major design goals for Falcon (Figure 1).
Fast: One of the most important requirements of cloud APIs is that they should respond to requests as quickly as possible. This becomes a critical feature in real-time scenarios when the number of concurrent requests is high. Falcon is one of the fastest frameworks available.

Light: A framework with a long trail of dependencies becomes very difficult to incorporate in various environments due to the restrictions imposed by the dependencies. Falcon has only two dependencies: six (a Python 2 and 3 compatibility library, which facilitates the code bases to work on both Python 2 and 3 without requiring any changes) and mimeparse (which provides  functionalities such as mime-type name parsing). This makes Falcon easier to test and deploy.
Flexible: Falcon doesn’t restrict developers when choosing libraries with respect to databases, authorisation, etc. Developers can select their preferred libraries, which match the requirements of the current project’s scenario.

figure-1-falcon-design-goals
Figure 1: Falcon design goals
figure-2-wsgi-server
Figure 2: WSGI servers

Falcon’s feature set
Some of the major features of Falcon are listed below:

  • Clean and extensible code base
  • Simple and quick access to headers and bodies
  • Simple and effective exception handling
  • Support for various versions of Cpython, PyPy and Jython
  • When used with Cython, the average increase in speed has been around 20 per cent

Installation
As stated earlier, Falcon is a high-performance framework. Official documentation recommends the use of PyPy to achieve optimal performance. PyPy is an alternative implementation of Python, which is comparatively faster. Speed, memory usage and compatibility are its major features. To explore further, navigate to http://pypy.org/.

The installation of Falcon is simple and quick. It can be installed using Pip, as shown below:

$ pip install falcon

Web Server Gateway Interface (WSGI)
Falcon communicates through WSGI, which is a specification used for interfacing Web servers and Web applications or frameworks for the Python language. WSGI was built to promote portable Web application development. Two major advantages of WSGI are listed below:

  • The use of WSGI increases the flexibility. App developers can swap out Web stack components for others.
  • It offers better scaling features. When the number of concurrent requests is great, the WSGI servers facilitate efficient scaling by segregating the responsibilities.

To provide a Falcon app, we need a WSGI server.  There are many choices listed in http://wsgi.readthedocs.io/en/latest/servers.html. The popular ones among the developer community are featured in Figure 2 and listed below.

Installation of any one of these WSGI servers is required for Falcon. You may choose gunicorn or uwsgi, and install them using the Pip command as shown below:

$pip install gunicorn

Falcon – a simple example
To run a Falcon app, you simply need to install Falcon and Gunicorn using Pip commands. Let’s consider a simple example that displays a message.

# things.py
# Import the Falcon
import falcon
class ThingsResource(object):
def on_get(self, req, resp):
“””Handles GET requests”””
resp.status = falcon.HTTP_200
resp.body = (‘\nTwo things awe me most, the starry sky ‘
‘above me and the moral law within me.\n’
‘\n’
‘    ~ Immanuel Kant\n\n’)
# falcon.API instances are callable WSGI apps
app = falcon.API()
# Resources are represented by long-lived class instances
things = ThingsResource()
# things will handle all requests to the ‘/things’ URL path
app.add_route(‘/things’, things)

To run this code, use the following command:

$gunicorn things:app

The output can be viewed by directly opening a browser and navigating to the URL, localhost:8000/things (as shown in Figure 3).

Otherwise, the output may be viewed through a terminal with the help of Curl, as shown below:

$curl localhost:8000/things
figure-3-simple-falcon-code
Figure 3: Simple Falcon code — browser output
figure-4-output-at-the-terminal-using-curl
Figure 4: Output at the terminal using Curl

Understanding Falcon terminology
Falcon terminology is inspired by the REST architectural style. If you already have some exposure to this architectural style then Falcon should feel very familiar to you.  But even if you have no clue about REST, etc, it is not difficult to understand Falcon.

Primarily, Falcon maps the incoming resources to entities called ‘resources’. Resources are nothing but Python classes, which include a few methods and a specific naming convention.  For any HTTP method that you plan your resource to support, you have to add an ‘on_x’ class method to the resource. The ‘x’ here indicates any one of the standard HTTP methods listed below:

  • on_get
  • on_put
  • on_head

The methods need to be in lower case. These popular methods are called ‘responders’. The responders have two parameters. One indicates the HTTP request and the other indicates the HTTP response to the request.

The request object can be used to read the headers, query parameters and the request body. The following code snippet illustrates response handling:

def on_get(self, req, resp):
resp.data = msgpack.packb({'message': 'Hello world!'})
resp.content_type = 'application/msgpack'
resp.status = falcon.HTTP_200

The code snippet to handle a POST request and store an image is shown below:

 

import os
import uuid
import mimetypes

import falcon

class Resource(object):

def __init__(self, storage_path):
self.storage_path = storage_path

def on_post(self, req, resp):
ext = mimetypes.guess_extension(req.content_type)
filename = '{uuid}{ext}'.format(uuid=uuid.uuid4(), ext=ext)
image_path = os.path.join(self.storage_path, filename)

with open(image_path, 'wb') as image_file:
while True:
chunk = req.stream.read(4096)
if not chunk:
break
image_file.write(chunk)

resp.status = falcon.HTTP_201
resp.location = '/images/' + filename

After this, fire a POST request as shown below:

$ http POST localhost:8000/images Content-Type:image/jpeg < yourfile.jpg

Replace yourfile.jpg with the name of the file you want to POST.  You may notice that the storage directory that you have specified in the code has a copy of the image yourfile.jpg.  Similarly, GET can also be processed. The complete code snippet is available at http://falcon.readthedocs.io/en/stable/user/tutorial.html.

Falcon error handling
Falcon offers a set of exceptions that you can raise when something doesn’t go as per plan.  The following items may be used for this purpose:

falcon.HTTPBadGateway
falcon.HTTPBadRequest
falcon.HTTPConflict
falcon.HTTPError
falcon.HTTPForbidden
falcon.HTTPInternalServerError
falcon.HTTPLengthRequired
falcon.HTTPMethodNotAllowed
falcon.HTTPNotAcceptable
falcon.HTTPNotFound
falcon.HTTPPreconditionFailed
falcon.HTTPRangeNotSatisfiable
falcon.HTTPServiceUnavailable
falcon.HTTPUnauthorized
falcon.HTTPUnsupportedMediaType
falcon.HTTPUpgradeRequired

A code snippet to handle the HTTPNotFound is shown below:

try:
resp.stream = open(image_path, ‘rb’)
except IOError:
raise falcon.HTTPNotFound()

To summarise, Falcon is handy when you want to set the dependencies to the lowest possible level. Its high performance with a clean REST architectural style makes it a good option to try out. One other major advantage of using Falcon, apart from it being lightweight and high in performance, is the availability of extensive documentation and an active community.

LEAVE A REPLY

Please enter your comment!
Please enter your name here