×
Community Blog Building Very Fast App Backends with Falcon Web Framework on PyPy

Building Very Fast App Backends with Falcon Web Framework on PyPy

In this article, we will be developing and deploying a REST API in Python using Falcon web framework on PyPy.

By Raushan Raj, Alibaba Cloud Tech Share Author. Tech Share is Alibaba Cloud's incentive program to encourage the sharing of technical knowledge and best practices within the cloud community.

In this article, we are going to quickly build and deploy a blazing fast REST API in Python web framework using Falcon. While walking through this article you will first learn the basics of Falcon framework, installing it on Alibaba Cloud Elastic Compute Service (ECS), building a Rest API for the app and finally deploying the app on the cloud.

Introduction: What Is Falcon?

Falcon is a minimalist WSGI library for building speedy web APIs and app backends. When it comes to building HTTP APIs, other frameworks weigh you down with tons of dependencies and unnecessary abstractions. Falcon cuts to the chase with a clean design that embraces HTTP and the REST architectural style.

The first thing that comes to your mind is probably "Why should I use Falcon?" Well, Falcon is as powerful as other python's frameworks like a flask, Django, bottle, web.py, and it is fast, extensible, reliable, and encourages RESTful style. As per benchmarks, Falcon is 21 times faster on pypy than flask and Django. Organizations like LinkedIn, Leadpages, Wargaming, and Rackspace are already using it in their applications.

1

Installing Falcon on Alibaba Cloud ECS

Installing Falcon on Alibaba Elastic Compute Service (ECS) is as simple as installing it in your PC.

Provisioning Ubuntu 16.04 on Alibaba ECS

You can refer the steps to provisioning your server using this tutorial Setup up Ubuntu Server on Alibaba_Cloud.

Installing pypy3 and dependencies on Ubuntu 16.04

"If you want your code to run faster, you should probably just use PyPy.??Guido van Rossum

  1. Speed: Python programs often run faster on PyPy. (What is a JIT compiler?)
  2. Memory usage: memory-hungry Python programs (several hundreds of MBs or more) might end up taking less space than they do in CPython.
  3. Compatibility: PyPy is highly compatible with existing python code. It supports cffi and can run popular python libraries like twisted and Django.
  4. Stackless: PyPy comes by default with support for stackless mode, providing micro-threads for massive concurrency.
$ sudo apt-get install python3-dev
$ wget https://bitbucket.org/pypy/pypy/downloads/pypy3-v6.0.0-linux64.tar.bz2
$ tar -xvf pypy3-v6.0.0-linux64.tar.bz2  -C /opt
$ sudo ln -s /opt/pypy3-v6.0.0-linux64/bin/pypy3 /usr/local/bin/pypy3
$ sudo chown -R <youruser>:<yourgroup> pypy3-v6.0.0-linux64/
$ pypy3
Python 3.5.3 (fdd60ed87e94, Apr 24 2018, 06:10:04)
[PyPy 6.0.0 with GCC 6.2.0 20160901] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>> import this

Once pypy3 is installed we have to install python dependencies compatible with pypy3's pip.

$ wget https://bootstrap.pypa.io/get-pip.py
$ pypy3 get-pip.py   # pypy3 -m ensurepip   
$ sudo apt-get install python3-pip
$ pip3 install virtualenvwrapper

Install virtualenvwrapper.

Append following line to .bashrc or .profile.

export WORKON_HOME=$HOME/.virtualenvs
export PROJECT_HOME=$HOME/Devel
source /usr/local/bin/virtualenvwrapper.sh

It's better to install python dependencies in virtualenv.

$ mkvirtualenv -p /usr/local/bin/pypy3 falconenv
(falconenv):~$ pypy3 -m pip install falcon mongoengine

Installing Mongodb on Ubuntu 16.04

MongoDB is an open-source document database that provides high performance, high availability, and automatic scaling.

$ sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv EA312927
$ echo "deb http://repo.mongodb.org/apt/ubuntu xenial/mongodb-org/3.2 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-3.2.list
$ sudo apt-get update
$ sudo apt-get install -y mongodb-org 
$ sudo systemctl start mongod  
$ sudo systemctl status mongod
# This command will start mongod. Other options are stop | restart | status. 
? mongodb.service - High-performance, schema-free document-oriented database
   Loaded: loaded (/etc/systemd/system/mongodb.service; enabled; vendor preset: enabled)
   Active: active (running) since Mon 2016-04-25 14:57:20 EDT; 1min 30s ago
 Main PID: 4093 (mongod)
    Tasks: 16 (limit: 512)
   Memory: 47.1M
      CPU: 1.224s
   CGroup: /system.slice/mongodb.service
           ??4093 /usr/bin/mongod --quiet --config /etc/mongod.conf

Building REST API

We are going to create a book project where the user can create a book, update book and fetch book by id from MongoDB.

Directory structure for falcon app

2

book_project/book/ has following python files.

models : In models we used mongoengine ORM. Any class that inherits Document class of mongoengine describes the equivalent collection in MongoDB database. We have created a resource Book with the field name, ISBN, and author. Mongoengine will autogenerate unique id for each object of the resource.

from mongoengine import StringField, IntField, Document

class Book(Document):
    name = StringField()
    isbn = IntField()
    author= StringField()

api : Book resource have enpoint methods on_get, on_post. Usage of each method is described in code comments below.

api.py source code is a below.

import falcon, json
from .models import Book

class BookResource(object):
    def on_get(self,req,resp,book_id):
        '''
        :param req: A request object
        :param resp: A response object
        :param book_id: book_id received in http path to query book object
        :return:
        '''
        book_obj= Book.objects.get(id=book_id)
        #Query book collection to get a record with id = book_id
        resp.body = json.dumps({'author':book_obj.author,'name':book_obj.name,'isbn':book_obj.isbn})
        #It will set response body as a json object of book fields.
        resp.status = falcon.HTTP_200
        #Finally return 200 response on success

    def on_post(self,req,resp):
        '''
         This method will recevie the book data in request body in order to store it in database
        :param req: It contains json of book's author, name and isbn.
        :param resp:
        :return:
        '''
        book_data = req.media
        #req.media will deserialize json object
        book_obj=Book.objects.create(**book_data)
        #passing book_data to create method. It will create a database document in book collection.
        resp.body = json.dumps({'book_id':str(book_obj.id),'message':'book succesfully created'})
        resp.status=falcon.HTTP_200

GET request endpoint to get a book given id : http://<host>:<port>/<book_id>

3

POST request endpoint to create a book with data : http://<host>:<port>/<book_id> ,

{"author":<author_name>,"name":<book_name>, "isbn":<isbn>}

4

app: This is the entry point for HTTP requests, It contains routing to resources based on HTTP path and other configurations

import falcon
from mongoengine import connect
from .api import BookResource

connect('bookdb', host='127.0.0.1', port=27017)
app = application = falcon.API()
books = BookResource()
app.add_route('/book/{book_id}', books)
app.add_route('/books/', books)

connect(, host=, port=), this line will automatically create a connection to the mongodb database with given credentials. The connection will be globally use throughout the scope of an app.

app = application = falcon.API(), this line will create application instances that gunicorn (web application server) will autofind and act as an wsgi app.

books = BookResource(), this line will create and instance of the resource.

app.add_route('/book/{book_id}', books) and app.add_route('/books/', books), will route the http path and method to the respective methods of the resource.

Deploying Web App with Gunicorn and Nginx

Gunicorn

Gunicorn 'Green Unicorn' is a Python WSGI HTTP Server for UNIX. It's a pre-fork worker model. The Gunicorn server is broadly compatible with various web frameworks, simply implemented, light on server resources, and fairly speedy._

In simple terms, gunicorn understands HTTP requests and make it understandable to python applications by converting HTTP bytes to python objects.

Run gunicorn on your ubuntu machine using following commands.

(falconenv):~$ pypy3 -m pip install gunicorn
(falconenv):~/book_project$  gunicorn --reload book.app --bind 127.0.0.1:9000

Nginx

NGINX is open source software for web serving, reverse proxying, caching, load balancing, media streaming, and more. It started out as a web server designed for maximum performance and stability. In addition to its HTTP server capabilities, NGINX can also function as a proxy server for email (IMAP, POP3, and SMTP) and a reverse proxy and load balancer for HTTP, TCP, and UDP servers.

Describing in Simple terms, nginx is a software that receives HTTP request bytes and sends HTTP response bytes to the client. Nginx is responsible to forward HTTP request bytes to python application server(gunicorn).

$ sudo apt-get install nginx

sudo vim falcon_nginx.conf

upstream falcon_gunicorn {
    server 127.0.0.1:9000;
}
 
server {
    listen  80;
    server_name <ALIBABA ECS instance public ip>;
    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;
    
    location / {
            proxy_pass         http://falcon_gunicorn;
            proxy_redirect     off;
            proxy_set_header   Host $host;
    }
}
$ sudo cp falcon_nginx.conf /etc/nginx/sites-enabled/nginx.conf
$ sudo service nginx restart

Summary

In order to develop and quickly deploy a REST API, Falcon proves to be one of the best alternatives. We need to install pypy3, falcon, MongoDB, gunicorn, Nginx and other dependencies on Alibaba Cloud's Elastic Compute Service (ECS) Ubuntu Server. API syntax for falcon is totally based on REST architecture and is very easy to develop with proper routing, model structure, and views. Falcon is a scalable solution and can be easily deployed on any WSGI servers like gunicorn, uwsgi, and waitress. Adding Nginx on top of gunicorn server will make microservices scalable, distributed and secure.

2 1 0
Share on

Alibaba Clouder

2,599 posts | 762 followers

You may also like

Comments

5809870713234921 October 10, 2019 at 1:17 pm

Hi, the example is throwing an error, you may find it in the log file. Please, review the article so it work 100%. Thanks and regards! Keep doing this good work![2019-10-10 14:09:08 0100] [6356] [ERROR] Error handling request /booksTraceback (most recent call last): File "/Users/marti/PycharmProjects/nlpapi/venv/lib/python3.6/site-packages/gunicorn/workers/sync.py", line 135, in handle self.handle_request(listener, req, client, addr) File "/Users/marti/PycharmProjects/nlpapi/venv/lib/python3.6/site-packages/gunicorn/workers/sync.py", line 176, in handle_request respiter = self.wsgi(environ, resp.start_response) File "/Users/marti/PycharmProjects/nlpapi/venv/lib/python3.6/site-packages/falcon/api.py", line 269, in call responder(req, resp, **params)TypeError: on_get() missing 1 required positional argument: 'book_id'

Arman Ali May 26, 2021 at 8:42 am

Thanks for this guide.