diff options
Diffstat (limited to 'vendor/CherryPy-3.2.0/sphinx/source/progguide/REST.rst')
-rw-r--r-- | vendor/CherryPy-3.2.0/sphinx/source/progguide/REST.rst | 255 |
1 files changed, 255 insertions, 0 deletions
diff --git a/vendor/CherryPy-3.2.0/sphinx/source/progguide/REST.rst b/vendor/CherryPy-3.2.0/sphinx/source/progguide/REST.rst new file mode 100644 index 0000000..2a2cf54 --- /dev/null +++ b/vendor/CherryPy-3.2.0/sphinx/source/progguide/REST.rst @@ -0,0 +1,255 @@ +***************************************** +Creating RESTful applications in CherryPy +***************************************** + +Introduction +============ + +REST (Representational State Transfer) is an architectural style that +is well-suited to implementation in CherryPy. Both REST and CherryPy +heavily leverage the HTTP protocol but otherwise carry minimal +requisite overhead. This chapter briefly discusses the purpose of +REST and an example implementation in CherryPy. + +REST in a nutshell +================== + +The REST architectural style describes how domain models and their state +are referenced and transferred. The primary goal of REST is promote +certain advantageous qualities of a distributed system, namely high +visibility, scalability, extensibility. + +Terminology +----------- + + - "resources" are concepual objects represented by the system - any + information that can be named is a resource. + - "state" is data held by or associated with resources + - "representations" are information in state with a specific encoding + - "methods" are invoked to transfer or mutate state. + - an "identifier" is a URL or URI which uniquely and usually globally + references a resource. + +More information on REST can be found in abundance in Wikipedia and +other readily-available resources. + +Implementing REST in CherryPy +============================= + +From the canonical `Roy Fielding dissertation <http://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm#sec_5_1_5>`_ : + + REST is defined by four interface constraints: identification of resources; + manipulation of resources through representations; self-descriptive messages; + and, hypermedia as the engine of application state + +This section covers each of these four contstraints and demonstrates how each +is applied in a CherryPy implementation. + +Identification of Resources +--------------------------- + +As an HTTP service provider, resources represented in CherryPy are +referenced by HTTP URIs (Uniform Resource Identifiers). A URI consists +of four parts: scheme, hierarchical identifier, query, and fragment. +For HTTP, the scheme is always ``http`` or ``https``. The hierarchical +identifier consists of an authority (typically host/port) and a path +(similar to a file system path, but not necessarily representing an +actual path). + +A single CherryPy instance is typically bound to a single +server/port pair, such that the scheme://authority portion of the URI +references the server. This aspect is configured through the +``server.socket_host`` and ``server.socket_port`` options or via another +hosting server. + +Within the CherryPy server, the remainder of the hierarchical +identifier--the path--is mapped to Python objects +via the Dispatch mechanism. This behavior is highly +customizable and documented in :doc:`/concepts/dispatching`. + +Using the default dispatcher and page handlers, the path of the URI +maps to a hierarchy of Python identifiers in the CherryPy app. For +example, the URI path ``/container/objects/pencil`` will result in a +call to ``app.root.container.objects.pencil()`` where ``app`` is the +CherryPy app. + +Manipulation of Resources Through Representations +------------------------------------------------- + +REST defines the use of the HTTP protocol and HTTP methods to implement +the standard REST methods. + + - GET retrieves the state of a specific resource, + - PUT creates or replaces the state of a specific resource, + - POST passes information to a resource to use at it sees fit, + - DELETE removes resources. + +The default dispatcher in CherryPy stores the HTTP method name at +:attr:`cherrypy.request.method<cherrypy._cprequest.Request.method>`. + +Because HTTP defines these invocation methods, the most direct +way to implement REST using CherryPy is to utilize the +:class:`MethodDispatcher<cherrypy._cpdispatch.MethodDispatcher>` +instead of the default dispatcher. To enable +the method dispatcher, add the +following to your configuration for the root URI ("/"):: + + '/': { + 'request.dispatch': cherrypy.dispatch.MethodDispatcher(), + } + +Now, the REST methods will map directly to the same method names on +your resources. That is, a GET method on a CherryPy class implements +the HTTP GET on the resource represented by that class. + +For example:: + + class Resource(object): + + exposed = True + + def GET(self): + return """Some representation of self""" + + def PUT(self): + self.content = initialize_from_representation(cherrypy.request.body.read()) + +The concrete implementation of GET and PUT has been omitted, but the +basic concepts remain: GET returns some meaningful representation of +the resource and PUT stores an instance of an object represented by the +content in the body of the request. + +Self-Descriptive Messages +------------------------- + +REST enables powerful clients and intermediaries by requiring messages to be +self-descriptive; that is, everything you need to know about a message is +carried within the message itself, either in headers or within the definition +of the message's declared media type. + +CherryPy gives you easy access to the headers. It's as simple as +:attr:`cherrypy.request.headers<cherrypy._cprequest.Request.headers>` and +:attr:`cherrypy.response.headers<cherrypy._cprequest.Response.headers>`! +Each is a normal Python dictionary which you can read and write as you like. +They also have additional functions to help you parse complex values according +to the HTTP spec. + +CherryPy also allows you to set whatever response Content-Type you prefer, +just like any other response header. You have complete control. When reading +request entities, you can register :ref:`custombodyprocessors` for different +media types. + +Hypermedia as the Engine of Application State +--------------------------------------------- + +REST is designed as a stateless protocol--all application state is +maintained with the application at the client. Thus, concepts such as a +"session" need not be maintained by the server. CherryPy does not enable +sessions by default, so it is well-suited to the RESTful style. + +In order for the client to maintain meaningful state, however, the REST +server implementer must provide meaningful URIs which supply semantic +links between resources. + +For example, a CherryPy application might have a resource index, which +a client might retrieve to inspect the application for other resources:: + + class ResourceIndex(object): + def GET(self): + items = [item.get_href() for item in self.get_all_items()] + return ', '.join(items) + +This very simple example demonstrates how to create an index of +comma-separated hypertext references. This example assumes the client +can effectively interpret comma-separated references. In practice, +another representation such as HTML or JSON might be used. + +A Quick Example +=============== + +For example, consider the following contrived REST+HTML specification. + +1. Resources store arbitrary key/value pairs with unique keys + (represented as a Python dict). + +2. A GET request returns colon-separated key/value pairs in ``<div>`` + elements. + +3. A PUT request accepts colon-separated key/value pairs in ``<div>`` + elements. + +4. An index resource provides an HTML anchor tag (hypertext link) to objects + which it indexes (where the keys represent the names and the values + represent the link). + +A REST+HTML implementation was chosen for this example as HTML defines +relative links, which keeps the example simple yet functional. + +Complete Example +---------------- + +Brining the above code samples together and adding some basic +configuration results in the following program, which can be run +directly:: + + import cherrypy + + class Resource(object): + + def __init__(self, content): + self.content = content + + exposed = True + + def GET(self): + return self.to_html() + + def PUT(self): + self.content = self.from_html(cherrypy.request.body.read()) + + def to_html(self): + html_item = lambda (name,value): '<div>{name}:{value}</div>'.format(\*\*vars()) + items = map(html_item, self.content.items()) + items = ''.join(items) + return '<html>{items}</html>'.format(**vars()) + + @staticmethod + def from_html(data): + pattern = re.compile(r'\<div\>(?P<name>.*?)\:(?P<value>.*?)\</div\>') + items = [match.groups() for match in pattern.finditer(data)] + return dict(items) + + class ResourceIndex(Resource): + def to_html(self): + html_item = lambda (name,value): '<div><a href="{value}">{name}</a></div>'.format(\*\*vars()) + items = map(html_item, self.content.items()) + items = ''.join(items) + return '<html>{items}</html>'.format(**vars()) + + class Root(object): + pass + + root = Root() + + root.sidewinder = Resource({'color': 'red', 'weight': 176, 'type': 'stable'}) + root.teebird = Resource({'color': 'green', 'weight': 173, 'type': 'overstable'}) + root.blowfly = Resource({'color': 'purple', 'weight': 169, 'type': 'putter'}) + root.resource_index = ResourceIndex({'sidewinder': 'sidewinder', 'teebird': 'teebird', 'blowfly': 'blowfly'}) + + conf = { + 'global': { + 'server.socket_host': '0.0.0.0', + 'server.socket_port': 8000, + }, + '/': { + 'request.dispatch': cherrypy.dispatch.MethodDispatcher(), + } + } + + cherrypy.quickstart(root, '/', conf) + +Conclusion +========== + +CherryPy provides a straightforward interface for readily creating +RESTful interfaces. |