.. _rest: REST Controller =============== If you need to write controllers to interact with objects, using the ``RestController`` may help speed things up. It follows the Representational State Transfer Protocol, also known as REST, by routing the standard HTTP verbs of GET, POST, PUT, and DELETE to individual methods:: from pecan import expose from pecan.rest import RestController from mymodel import Book class BooksController(RestController): @expose() def get(self, id): book = Book.get(id) if not book: abort(404) return book.title URL Mapping ----------- By default, the ``RestController`` routes as follows: +-----------------+--------------------------------------------------------------+--------------------------------------------+ | Method | Description | Example Method(s) / URL(s) | +=================+==============================================================+============================================+ | get_one | Display one record. | GET /books/1 | +-----------------+--------------------------------------------------------------+--------------------------------------------+ | get_all | Display all records in a resource. | GET /books/ | +-----------------+--------------------------------------------------------------+--------------------------------------------+ | get | A combo of get_one and get_all. | GET /books/ | | | +--------------------------------------------+ | | | GET /books/1 | +-----------------+--------------------------------------------------------------+--------------------------------------------+ | new | Display a page to create a new resource. | GET /books/new | +-----------------+--------------------------------------------------------------+--------------------------------------------+ | edit | Display a page to edit an existing resource. | GET /books/1/edit | +-----------------+--------------------------------------------------------------+--------------------------------------------+ | post | Create a new record. | POST /books/ | +-----------------+--------------------------------------------------------------+--------------------------------------------+ | put | Update an existing record. | POST /books/1?_method=put | | | +--------------------------------------------+ | | | PUT /books/1 | +-----------------+--------------------------------------------------------------+--------------------------------------------+ | get_delete | Display a delete confirmation page. | GET /books/1/delete | +-----------------+--------------------------------------------------------------+--------------------------------------------+ | delete | Delete an existing record. | POST /books/1?_method=delete | | | +--------------------------------------------+ | | | DELETE /books/1 | +-----------------+--------------------------------------------------------------+--------------------------------------------+ Pecan's ``RestController`` uses the de-facto standard ``?_method=`` query string hack to work around the lack of PUT/DELETE support in current browsers. The ``RestController`` still supports the ``index``, ``_default``, and ``_lookup`` routing overrides. If you need to override ``_route``, however, make sure to call ``RestController._route`` at the end of your custom ``_route`` method so that the REST routing described above still occurs. Nesting ------- ``RestController`` instances can be nested so that child resources get the parameters necessary to look up parent resources. For example:: from pecan import expose from pecan.rest import RestController from mymodel import Author, Book class BooksController(RestController): @expose() def get(self, author_id, id): author = Author.get(author_id) if not author_id: abort(404) book = author.get_book(id) if not book: abort(404) return book.title class AuthorsController(RestController): books = BooksController() @expose() def get(self, id): author = Author.get(id) if not author: abort(404) return author.name class RootController(object): authors = AuthorsController() Accessing ``/authors/1/books/2`` would call ``BooksController.get`` with an ``author_id`` of 1 and ``id`` of 2. To determine which arguments are associated with the parent resource, Pecan looks at the ``get_one`` or ``get`` method signatures, in that order, in the parent controller. If the parent resource takes a variable number of arguments, Pecan will hand it everything up to the child resource controller name (e.g., ``books`` in the above example). Custom Actions -------------- In addition to the default methods defined above, you can add additional behaviors to a ``RestController`` by defining a special ``_custom_actions`` dictionary. For example:: from pecan import expose from pecan.rest import RestController from mymodel import Book class BooksController(RestController): _custom_actions = { 'checkout': ['POST'] } @expose() def checkout(self, id): book = Book.get(id) if not book: abort(404) book.checkout() Additional method names are the keys in the dictionary. The values are lists of valid HTTP verbs for those custom actions, including PUT and DELETE.