Day 25: Tornado–Combining Tornado, MongoDB, and AngularJS to Build an App

Today for my 30 day challenge, I decided to take a break from JavaScript and learn a web framework called Tornado.

I decided to learn Tornado to write a web application in Python. I only know the Flask framework so I thought Tornado would be a good addition to my Python web development skills. Today’s application uses Tornado for the REST backend, MongoDB as the database, AngularJS as the client side JavaScript MV* framework, and OpenShift as the deployment platform.

Tornado logo

What is Tornado?

Tornado is an open-source Python Web framework and non blocking web server, developed at FriendFeed. Facebook bought FriendFeed and continues to maintains and develops Tornado. It has excellent scalability characteristics due to its non-blocking network I/O nature and scales to thousands of simultaneous connections.

Application Usecase

In this blog post, we will develop a social bookmarking application which allows users to post and share links. You can view the live application running on OpenShift here. This is the same application which we developed on day 22 so please refer to the blog to better understand the application usecase.

Github Repository

The code for today’s demo application is available on github: day25-tornado-demo-app.

Prerequisite

Before we can get started with Tornado, we need to install Python and virtualenv on the machine. The Python version I am using in this blog post is 2.7.

This application uses MongoDB as data storage choice so please download the latest MongoDB release for your operation system.

Developing Tornado MongoDB Application

We will use the pip install to get started with Tornado. For developers unaware of pip, it is Python package manager. We can install pip from the official website. Go to any convenient directory on your file system, and run following commands.

$ mkdir getbookmarks
$ cd getbookmarks
$ virtualenv venv --python=python2.7
$ . venv/bin/activate
$ pip install tornado
$ pip install pymongo

Theses commands create a getbookmarks directory on the local machine, activate virtualenv with Python version 2.7, install the tornado package and install pymongo. The pymongo is the official MongoDB Python driver. We will use it to write stories into MongoDB.

Create a new file called getbookmarks.py under the getbookmarks folder.

$ touch getbookmarks.py

Copy the following code and paste it in the getbookmarks.py source file

import os
from tornado import ioloop,web
from pymongo import MongoClient
import json
from bson import json_util
from bson.objectid import ObjectId
 
class IndexHandler(web.RequestHandler):
    def get(self):
        self.write("Hello World!!")
 
settings = {
    "template_path": os.path.join(os.path.dirname(__file__), "templates"),
    "static_path": os.path.join(os.path.dirname(__file__), "static"),
    "debug" : True
}
 
application = web.Application([
    (r'/', IndexHandler),
    (r'/index', IndexHandler),
],**settings)
 
if __name__ == "__main__":
    application.listen(8888)
    ioloop.IOLoop.instance().start()

This code:

  1. Imports the required libraries.

  2. Defines a new class called IndexHandler which extends web.RequestHandler. A Tornado web applications maps URLs or URL patterns to subclasses of the web.RequestHandler class. These classes define get(), post(),etc. methods to handle HTTP GET or POST requests to that URL. When a GET request is made to the ‘/’ url, then IndexHandler will respond with “Hello World!!”.

  3. Defines some application settings. The template_path setting tells the Tornado application to look for application templates in the templates directory. The static_path setting informs the application to use the static directory for static assets like css, images, and javascript files. We also enable debugging by passing debug:True. The main benefit of the debugger is it automatically reloads changes. We can keep the debugger running in the background and work through our application. This provides a highly productive environment.

  4. Creates the Tornado application instance passing it the routes and settings.

  5. Starts application server using the python getbookmarks.py command.

Run the application using the command shown below. Go to http://localhost:8888 and http://localhost:8888/index to verify you see “Hello World!!”.

$ python getbookmarks.py

Configure MongoDB

Add the following lines after importing the libraries. We defined MongoDB connection url and database name. If the application is deployed on OpenShift then OpenShift specific environment variables will be used otherwise local machine configuration will be used.

MONGODB_DB_URL = os.environ.get('OPENSHIFT_MONGODB_DB_URL') if os.environ.get('OPENSHIFT_MONGODB_DB_URL') else 'mongodb://localhost:27017/'
MONGODB_DB_NAME = os.environ.get('OPENSHIFT_APP_NAME') if os.environ.get('OPENSHIFT_APP_NAME') else 'getbookmarks'
 
client = MongoClient(MONGODB_DB_URL)
db = client[MONGODB_DB_NAME]

We created an instance of MongoClient passing it the connection url. This connects it to the running mongod instance. Next we get the database using MongoClient instance.

Create and List All Stories

Now we will add functionality to create new stories and list all the stories. We will first add the route to Application instance as shown below.

application = web.Application([
    (r'/', IndexHandler),
    (r'/index', IndexHandler),
    (r'/api/v1/stories',StoriesHandler),
],**settings)

Next we will define the StoriesHandler which will be responsible for persisting stories into MongoDB and finding all the stories.

class StoriesHandler(web.RequestHandler):
    def get(self):
        stories = db.stories.find()
        self.set_header("Content-Type", "application/json")
        self.write(json.dumps(list(stories),default=json_util.default))
 
 
    def post(self):
        story_data = json.loads(self.request.body)
        story_id = db.stories.insert(story_data)
        print('story created with id ' + str(story_id))
        self.set_header("Content-Type", "application/json")
        self.set_status(201)

In the code shown above

  1. When a user makes a GET request to ‘/api/v1/stories’, then we make a find() call to MongoDB. As we are not specifying any query so it will fetch all the stories from MongoDB. We set the content type to “application/json” and dump the json response.

  2. When a user makes POST request to ‘/api/v1/stories’, then we first decode the json body to a dictionary and then write the data to MongoDB. We set the response status to 201(Created).

View Individual Story

The last backend functionality is to view the individual story. We first specify the route.

application = web.Application([
    (r'/', IndexHandler),
    (r'/index', IndexHandler),
    (r'/api/v1/stories',StoriesHandler),
    (r'/api/v1/stories/(.*)', StoryHandler)
],**settings)

Then we will write the StoryHandler

class StoryHandler(web.RequestHandler):
    def get(self , story_id):
        story = db.stories.find_one({"_id":ObjectId(str(story_id))})
        self.set_header("Content-Type", "application/json")
        self.write(json.dumps((story),default=json_util.default))

The code shown above finds the story corresponding the story_id and then dumps the json response.

AngularJS Front End

I decided to reuse the AngularJS front end which we wrote on day 22. The day 22 showcased how we can use AngularJS with Java Spring framework backend. The best part of using JavaScript MV* frameworks is that you can reuse the frontend code if your application stick to the REST interface client needs. Please read the day 22 blog for more information.

You can download the AngularJS front end from my github repository. Copy the static and templates folder and place it next to the getbookmarks.py.

Deploying Application to OpenShift

Before we deploy the application to OpenShift, we’ll have to do few setup tasks :

  1. Sign up for an OpenShift Account. It is completely free, and Red Hat gives every user three free Gears on which to run your applications. At the time of this writing, the combined resources allocated for each user is 1.5 GB of memory and 3 GB of disk space.

  2. Install the rhc client tool on the machine. The rhc is a ruby gem so you need to have ruby 1.8.7 or above on your machine. To install rhc, just typesudo gem install rhc
    If you already have one, make sure it is the latest one. To update the rhc, execute the command shown below.sudo gem update rhc
    For additional assistance setting up the rhc command-line tool, see the following page: https://openshift.redhat.com/community/developers/rhc-client-tools-install

  3. Setup the OpenShift account using rhc setup command. This command will help us create a namespace and upload your ssh keys to OpenShift server.

After setup, we can create a new OpenShift application by running the following command.

$ rhc create-app day25demo python-2.7 mongodb-2 --from-code https://github.com/shekhargulati/day25-tornado-demo-app.git

It will do all the stuff from creating an application, to setting up public DNS, to creating private git repository, and then finally deploying the application using code from my Github repository. The app is running here http://day25demo-shekhargulati.rhcloud.com/#/

That’s it for today. Keep giving feedback.

Next Steps

Categories
MongoDB, Python
Tags
,
Comments are closed.