Date

This quick tutorial is as much for my sake as for any potential readers. Compiled from the following sources, so you don't have to.

Passenger on Your Domain

This is covered in Dreamhost's wiki, but I'll quickly cover the steps. If you're using Passenger Wiki then you'll need to dedicate an entire Domain/Sub-Domain to the WSGI application. I created a quick subdomain: apitest.hpincket.com When you do, check the box which enables Passenger WSGI. This is an alternative to the tutorial-used Gunicorn WSGI. They automatically create a directory 'public/' for static resources.

Setting up Virtualenv

I found 'pip' already installed. Yay! Go ahead and install virtualenv if it isn't already.

$ pip install virtualenv

Navigate to your newly created sub-domain.

$ cd ~/apitest.hpincket.com
$ ls
    public

Create your virtual environment.

$ virtualenv venv
$ source venv/bin/activate

Install Falcon and any other dependencies you might need.

$ (venv) pip install falcon
$ (venv) pip install requests
$ (venv) pip install more-stuff-i-need

Integrating Falcon

Passenger looks for a passenger_wsgi.py in your sub-domain's directory. This is equivalent gunicorn's run.py in the Falcon tutorial. This file needs an application variable to be run by the WSGI server. We already now how to acquire one of these.

import falcon
api = application = falcon.API()

But that requires us to import falcon, which is installed in our virtual environment, not system wide. To run Passenger in the correct environment add the following to the very top of passenger_wsgi.py:

# Virtual Env
import os, sys
INTERP = os.path.join(os.environ['HOME'], 'apitest.hpincket.com', 'venv', 'bin', 'python')
if sys.executable != INTERP:
        os.execl(INTERP, INTERP, *sys.argv)

The INTERP variable should point to the python file in your virtual environment. If using virtualenvwrapper then you will need to change the location to .virtualenvs.

If you ever need to make changes you can pkill python to restart the python app. Warning, I think this might affect any other apps you have running. This is just easy.

Example API

# ~/apitest.hpincket.com/passenger_wsgi.py
import os, sys

# Virtual Env
INTERP = os.path.join(os.environ['HOME'], 'apitest.hpincket.com', 'venv', 'bin', 'python')
if sys.executable != INTERP:
    os.execl(INTERP, INTERP, *sys.argv)

# Let's get this party started
import falcon
import things

# falcon.API instances are callable WSGI apps
api = application = falcon.API()

# Resources are represented by long-lived class instances
things_res = things.ThingsResource()

# things will handle all requests to the '/things' URL path
api.add_route('/things', things_res)
# ~/apitest.hpincket.com/things.py

import falcon

# Falcon follows the REST architectural style, meaning (among
# other things) that you think in terms of resources and state
# transitions, which map to HTTP verbs.
class ThingsResource:
    def on_get(self, req, resp):
        """Handles GET requests"""
        resp.status = falcon.HTTP_200  # This is the default status
        resp.body = ('\nTwo things awe me most, the starry sky '
                     'above me and the moral law within me.\n'
                     '\n'
                     '    ~ Immanuel Kant\n\n')

Go ahead and give it a TRY

Adding MySQL

Set-up a database on your domain. Instructions for this can be found here on Dreamhost's wiki.

Install the mysql-connector-python. There are alternatives to this, but it worked for me.

$ pip install mysql-connector-python
echo OR THIS ONE
$ pip install MySQLdb-python

Take a look at the following code.

# birds.py
import falcon
import json
import mysql.connector

# Falcon follows the REST architectural style, meaning (among
# other things) that you think in terms of resources and state
# transitions, which map to HTTP verbs.
class FalconsResource:
    def on_get(self, req, resp):
        """Handles GET requests"""
        resp.status = falcon.HTTP_200  # This is the default status
        try:
            cnx = mysql.connector.connect(user='database_user', password='user_password', database='created_database', host='mysql.domain.com')
            cursor = cnx.cursor()
            query = "SELECT * FROM `species`"
            cursor.execute(query)
            data = {}
            for (idnum ,common_name, latin_name) in cursor:
                data[common_name] = latin_name
            cursor.close()
            cnx.close()
            resp.body = json.dumps(data)
        except mysql.connector.Error as e:
        resp.body = "ERROR: {}".format(e)

You can see the result of this resource at apitest.hpincket.com/birds.