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.


== Quick Start ==

This document contains info on the bleeding edge version of Restler (0.3.x). See http://code.google.com/p/restler/wiki/QuickStartZeroDotTwo for info on the previous version (0.2a18).


=== Install Pylons 0.9.7 ===

{{{
easy_install Pylons==dev
}}}

Restler is developed against Pylons 0.9.7.


=== Install Restler ===

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


=== Create a new Pylons project ===

{{{
paster create --template=pylons MyProject
cd MyProject
}}}


=== Set up database engine, Session, and metadata ===

Not documented here. See Pylons docs.

TODO: Link to appropriate docs and/or show simple example here.


=== Create a base controller class ===

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

{{{
from restler.controller import Controller as _RestController
}}}

Next, create a new class that implements the `get_db_session` method:

{{{
class RestController(_RestController):

    def get_db_session(self):
        return myproject.model.meta.Session
}}}

Where you define your database session object/factory is up to you. The example here is based on a model setup suggested by members of the Pylons community.

Note: The default `BaseController` generated by `paster` when creating a new Pylons project is used by the default `error` and `template` controllers, so it's probably best to leave it alone and not use it as your RESTful base controller.


=== Create some mapped entity classes ===

Every entity class needs `member_name`, `member_title`, `collection_name`, and `collection_title` class attributes. 

To return JSON using the Restler controller's built-in facilities, entity classes need to define the methods `to_simple_object` and `to_simple_collection`. Restler provides an `Entity` base class with default implementations of these methods.

{{{
import restler.entity


class Garage(restler.entity.Entity):

    member_name = 'garage'
    collection_name = 'garages'
    member_title = 'Garage'
    collection_title = 'Garages'
    
    
# TODO: Create a SQLAlchemy `Table` object for the `Garage` class and map the
# class and table.
}}}

If you're using SQLAlchemy's declarative extension, you could do something like this instead:

{{{
from sqlalchemy import MetaData

from restler.entity import EntityMeta, Entity


metadata = MetaData()
Base = declarative_base(metaclass=EntityMeta, cls=Entity, metadata=metadata)


class Garage(Base):
    __tablename__ = 'garage'
    __table_args__ = dict(schema='trans')
    __mapper_args__ = dict(order_by='garage')
}}}

Restler's `EntityMeta` metaclass automagically adds `member_name`, `member_title`, etc. attributes to the class.

XXX: `Entity` has a tiny bit of direct dependency on both SQLAlchemy (`self._sa_instance_state`, `Column`) and the declarative extension (`get_column_default` method uses `__table__`). The latter should be removed entirely. The former should be removed if at all possible.


=== Create a controller for each Entity class you want to expose ===

{{{
from myproject.model.entities.oracle.trans import Garage
from myproject.lib.base import RestController


class GaragesController(RestController):

    entity = Garage
}}}


=== Map URLs for resources/entities to controllers ===

In config/routing.py, add a line like this for each RESTful controller:

{{{
map.resource('garage', 'garages')
}}}


=== Epilogue ===

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

Send feedback, corrections, et cetera to wyatt .DOT. lee .DOT. baldwin .AT. gmail .DOT. com or [http://code.google.com/p/restler/issues/list create an issue].
