REST support in Grok
Author: | Martijn Faassen |
---|
REST is a way to build web services, i.e. a web application where the user is another computer, not a human being. REST takes the approach to make the web service look very similar to a normal web application, using well-known semantics of HTTP.
Grok has support that helps you implement REST-based protocols. That is, Grok doesn't actually implement any RESTful protocols itself, but it allows you to easily add them in your own application.
To implement a REST protocol, you do something very similar to implementing a skin. This way, REST requests are separated from other requests on objects. This means you can have a normal web UI with views on a set of objects in parallel to the implementation of one or more REST protocols.
Let's see how you define a REST protocol. Similar to the way skins work, first you need to define a layer. In the case of REST, your layer must derive from grok.IRESTLayer:
class AtomPubLayer(grok.IRESTLayer): pass
REST handlers are very much like views like JSON or XMLRPC views. In the case of REST, you implement the HTTP methods on the view:
class MyREST(grok.REST): grok.context(MyContainer) def GET(self): return "GET request, retrieve container listing" def POST(self): return "POST request, add something to container" def PUT(self): return "PUT request, replace complete contents" def DELETE(self): return "DELETE request, delete this object entirely"
When handling a REST request, you often want to get to the raw body of the request. You can access a special body attributre that contains the body as a string:
class MyREST2(grok.REST): def POST(self): return "This is the body: " + self.body
This body should be parsed accordingly by your REST protocol implementation - it could for instance be some form of XML or JSON.
To actually issue REST requests over a URL, you need to define a REST protocol that uses this layer:
class AtomPubProtocol(grok.RESTProtocol): grok.layer(AtomPubLayer) grok.name('atompub') # a nicer name
Again this is very similar to the way skins work - in order to use a layer you need to define a grok.Skin first.
Now you can access the object with the REST protocol, through requests like this (issuing GET, POST, PUT or DELETE):
http://localhost:8080/++rest++atompub/mycontainer
As you can see, you need to use the ++rest++<protocolname> pattern somewhere in the URL in order to access the REST view for your objects. If you don't like the ++rest++ bit you can also provide (directlyProvides) the layer manually to the request during traversal, or if you're using Apache, use a few rewrite rules. (just like with skins).
Using protocols like this means you could have a single object implement several different REST protocols. Since layers are used, you could also compose a single REST protocols out of multiple protocols should you so desire.
If you don't explicitly set a layer using grok.layer for a REST subclass, it'll use the grok.IRESTLayer by default. This layer is the base of all REST layers.
Similar again to XMLRPC or JSON views, security works with all this: you can use @grok.require() on the REST methods to shield them from public use.