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
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.
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.
- Green Unicorn (Gunicorn): This is a Python WSGI HTTP server for UNIX. The Gunicorn server is compatible with various Web frameworks. (http://gunicorn.org/)
- uWSGI: The objective of the uWSGI project is to provide a full stack for building hosting services. (http://uwsgi-docs.readthedocs.io/en/latest/)
- mod_wsgi: This is an Apache module, which implements the WSGI specification. (https://github.com/GrahamDumpleton/mod_wsgi)
- CherryPy: This is a Pythonic WSGI server with object-oriented features. (https://github.com/cherrypy/cherrypy)
- Julep: This is a WSGI server, which has been inspired by Unicorn and is written in pure Python. (https://code.google.com/archive/p/julep/)
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
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.