What's new? | Help | Directory | Sign in
Google
restler
RESTful base controller for Pylons
  
  
  
  
    
Join project
Project owners:
  wyatt.lee.baldwin

RESTful + Controller = Restler

Restler is a base controller for Pylons projects that provides a set of default RESTful actions that can be overridden as needed. It also handles database connectivity as long as a few simple rules are followed.

It adds a bit of 'convention-over-configuration' to Pylons and takes some inspiration from Rails' scaffold_resource generator. Templates aren't generated at this time, but a set of default generic templates are supplied which can be copied and modified to suit.

assignmapper1 model classes are required. This means you can also use Elixir, since Elixir uses assignmapper "under the hood." If you're looking for the most "Rails-esque" experience, you'll probably want to use Elixir.

--

1. assignmapper: http://www.sqlalchemy.org/docs/03/plugins.html#plugins_assignmapper

Quick Start

Install Pylons 0.9.5 or Newer

easy_install Pylons>=0.9.5

Development of Restler is currently done with Pylons 0.9.6rc2.

Install Restler

easy_install -U Restler

Or, install from SVN:

svn checkout http://restler.googlecode.com/svn/trunk/ Restler
cd Restler
python setup.py develop

Note: If you have problems with the easy_installed version of Restler, try the SVN version, which may have fixes that I haven't yet uploaded to PyPI.

Create a new Pylons project

paster create --template=pylons MyProject
cd MyProject

Add your database configuration to development.ini

Add a line like this to the [app:main] section:

sqlalchemy.dburi = <db_type>://<user>:<password>@<host>/<database>

Replace <db_type>, <user>, <password>, <host>, and <database> to reflect your setup. For example:

sqlalchemy.dburi = sqlite:///%(here)s/myproject.db

Make your project Restler aware

Open myproject/lib/base.py and add the following lines below the existing imports:

import restler
RestController = restler.BaseController(model)

You can also create a new RestController class in lib.base that inherits from restler.BaseController. First, remove the line RestController = restler.BaseController(model) added above, then add a class like this (which shows a quick and dirty way to secure the new, edit, and delete actions for all controllers):

class RestController(restler.BaseController(model)):
    def __call__(self, environ, start_response):
        return super(RestController, self).__call__(environ, start_response)

    def new(self):
        abort(403)
    edit = delete = new

In real life, you'll probably want to use AuthKit or something similar to protect these actions.

Note: Don't remove the default BaseController; it's needed by the error and template controllers.

Declare one or more ActiveMapper or Elixir Entity classes in model/init.py

I prefer Elixir, so that's what this example uses.

from elixir import metadata, Entity, has_field, has_many, belongs_to
from elixir import String, Integer

class Directory(Entity):
    '''A `Directory` contains `Page`s.'''
    has_field('title', String(40))
    has_field('slug', String(20))
    has_many('pages', of_kind='Page')

class Page(Entity):
    '''A `Page` belongs to a `Directory`.'''
    has_field('title', String(40))
    has_field('slug', String(20))
    has_field('content', String)
    has_field('sidebar', String)
    belongs_to('directory', of_kind='Directory')

Entity classes should use the 'member name' of their associated resources ('Page' in this example).

Create a controller for each of the Entity classes declared above

Use the 'collection name' of the associated resource as the controller name:

# directories.py
from myproject.lib.base import *
class DirectoriesController(RestController): pass

# pages.py
from myproject.lib.base import *
class PagesController(RestController): pass

Map URLs for resources/entities to controllers

Add routes to myproject/config/routing.py for each of the Entity classes declared above. Add them right below the default 'error' route. You might want to remove the default :controller/:action/:id route

map.resource('directory', 'directories')  # member name, collection name
map.resource('page', 'pages',
    parent_resource={'member_name': 'directory', 'collection_name': 'directories'})

Create the database tables for the entity classes you declared above

Open myproject/websetup.py and add these imports:

import sqlalchemy
import myproject.model as model

Add this line to the bottom of the setup_config function:

    engine = sqlalchemy.create_engine(conf['sqlalchemy.dburi'])
    engine.echo = True
    model.metadata.connect(engine)
    drop_all_tables()
    create_all_tables()

Add these functions, then close websetup.py:

def drop_all_tables():
    really_drop = raw_input('Really drop all tables?! [yes/N] ')
    if really_drop.lower().strip() == 'yes':
        print 'Dropping all tables...'
        model.metadata.drop_all()
    else:
        print 'Tables not dropped'

def create_all_tables():
    print 'Creating all tables...'
    model.metadata.create_all()
    print 'Done creating all tables.'

Run this command:

paster setup-app development.ini

Create templates for the basic CRUD actions

Actually, instead of creating templates, you can just use Restler's default templates. There are a few ways to do this.

  1. Locate the Restler installation directory in your python2.x/site-packages folder and copy the directory /path/to/restler/templates/defaults to your project's templates folder, myproject/templates/defaults
  2. Create a symbolic link from myproject/templates/defaults to /path/to/restler/templates/defaults
  3. If your project is in a Subversion repository, you can use svn:externals like this:
  4. cd myproject/templates
    svn propedit svn:externals .
    Add this line to the file that opens:
        defaults http://restler.googlecode.com/svn/trunk/restler/templates/defaults
    Save, quit, and `svn up`

Using Restler's default templates requires importing Restler's helpers. Add the following import to myproject/lib/helpers.py:

from restler.helpers import *

You might want to use Restler's default stylesheet and images. To do so, copy the images, javascripts, and stylesheets directories from /path/to/restler/public to myproject/public.

To create your own templates, make subdirectories in your project's templates directory using each resource's collection name. For the Directory model, you'd create myproject/templates/directories; for the Page model, you'd create myproject/templates/pages. Templates added to these directories will override templates with the same name in the defaults directory, so you can selectively override the defaults.

Fire up your Pylons app and try it out

paster serve --reload development.ini

You should now be able to Create, Read, Update, and Delete resources.

Look at all the things I'm not doing

Of course, as you customize your app and it gets more complex, you'll have to modify the basic setup, but it's a good starting point (at least, it's supposed to be; if you find that it's not, please do make an issue out of it).

Epilogue

Restler was extracted from the byCycle.org Bicycle Trip Planner (http://tripplanner.bycycle.org).

Send feedback, corrections, et cetera to wyatt .DOT. lee .DOT. baldwin .AT. gmail .DOT. com or create an issue.