[Grok-dev] Re: Is there an easy way to customize URL used for
grok.REST (use suffix instead of prefix) ?
Martijn Faassen
faassen at startifact.com
Mon Jun 2 08:46:36 EDT 2008
Craeg Strong wrote:
> Using the excellent REST tutorial I was able to create a REST adapter
> that returns XML content in response to
> an HTTP "GET" request at
> http://localhost:8080/++rest++xml/myapp/mycontainer
>
> However, I would like to use simple relative URLs in my javascript like
> 'xml'
>
> Ext.onReady(function() {
>
> var proxy = new Ext.data.HttpProxy({ url: 'xml', method:'GET'});
>
> In my browser-side code, it seems to be much easier to construct a
> relative url simply by appending a suffix (such as 'xml') to the URL,
> rather than parsing the URL and inserting a prefix in between the
> host+port and path
>
> The documentation provides a tantalizing hint: "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"
>
> But I am having trouble figuring out how to marry grok.Traverser with
> grok.REST.
>
> Can anyone provide a bread crumb for me to follow?
Okay, your use case is a bit different than the one I wrote the hint
for. I've seen something close to this use case before though (hi
Jasper). The idea is that you can do the following:
@grok.subscribe(MyApp, IBeforeTraverseEvent)
def restSkin(obj, event):
if not MyLayer.providedBy(event.request)
zope.publisher.http.applySkin(event.request,
MyLayer, grok.IRESTSkinType)
(note that the import path of applySkin changes in Grok 0.13, to be
released, due to some changes in Zope 3, but the principle will be the same)
This says that before you traverse into MyApp, the MyLayer rest protocol
needs to be applied to the request (if it's not already supplied).
The problem in your case is that you want *part* of your application to
be restful, and parts presumably just show the original UI. This is what
the whole skin/rest protocol system is for - you can really reliably
split both domains from each other.
I agree though that it's frustrating to have to insert the ++rest++foo
bit in the URL space and that it'd be nicer to construct relative URLs.
You could see this as partitioning your resource space. Some resources
(you call it 'xml') are REST-only, others are non-REST.
You could accomplish something like this by using traversing behavior
(you can use a custom grok.Traverser on an interface to make this more
universal):
class MyContainer(grok.Container):
def traverse(self, name):
if name == 'xml':
return ContainerXml(self)
class ContainerXml(grok.Model):
def __init__(self, context):
self.context = context
@grok.subscribe(ContainerXml, IBeforeTraverseEvent)
def restSkin(obj, event):
... apply the rest skin
You then attach your REST view to ContainerXml, which can talk to the
container through its context.
I *think* this should work; the only bit I'm a bit unsure about is when
IBeforeTraverseEvent is applied here; it might confuse things. An
alternative is to set the skin in the 'traverse' method in MyContainer
(you need a grok.Traverser subclass for that, actually, as you need
access to the request).
If this pattern is common enough, we might want to abstract this whole
pattern out into something like a 'RelativeRestResource' or something. I
can imagine people would want something similar for JSON and XMLRPC as
well, though it's less important to keep the URL spaces separate in that
case.
Regards,
Martijn
More information about the Grok-dev
mailing list