Sunday, November 11, 2007

REST in Pylons needs work.

RESTful controllers, in Pylons 0.9.6.1, are second class citizens.

The issue is, Routes does not support nested dispatching to a depth > 1. This means if you want to build a RESTful API which looks like this:

/users/{user_name}/collections/{collection_name}/items/{item_name}

you are bang out of luck. No dice. Can't do it. You are restricted to:

/users/{user_name}/collections/{collection_name}

which is an artificial restriction, which gets in the way. Blocks the whole road, in fact.

pylonshq.com states that, if you don't like the behavior of routes, you can 'plug in your favorite' dispatcher. This is much harder than it sounds, as the WSGIController classes you've probably already written likely depend on information coming from the routes layer. IMO this makes routes (in the context of Pylons) part of the application. It is not middleware.

It would be great if someone could please tell me I'm wrong, and show me the way!

9 comments:

gaspode said...

There's a nested_resource option in Routes, look under the resource docs for Routes. Is that what you're referring to?

Simon Wittber said...

Yes, this is what I am referring to.

The parent_resource argument does allow the programmer to create a nested resource. However, it only works one level deep, which is the problem.

Mark said...

Last week at a TurboGears 2 sprint, we added TG/CherryPy style object dispatch controller to pylons, on top of routes.

We just setup a route that sends the rest of the path to our controller and then we do dispatch from there.

It wasn't trivial, but it wasn't that hard either. And the results are in the current dev version of pylons, so you can take a look if you want.

And our new object dispatch controller makes it easy to lookup something, create an object and dispatch on that, so you can nest things as deeply as you need to.

Read more about the lookup method at:

http://docs.turbogears.org/2.0/RoughDocs/ObjectDispatch

Mark said...

Last week at a TurboGears 2 sprint, we added TG/CherryPy style object dispatch controller to pylons, on top of routes.

We just setup a route that sends the rest of the path to our controller and then we do dispatch from there.

It wasn't trivial, but it wasn't that hard either. And the results are in the current dev version of pylons, so you can take a look if you want.

And the object dispatch mechanism is much improved, so it's easy to lookup something in the database, create an object and dispatch on that, so you can nest things as deeply as you need to.

madpilot said...

Hi Simon

Rails has supported multiple nested routes for a while, however, they have fallen out of favour because they are rarely needed.

In the example you give, either the user or the collection is redundant (depending on the models you use)

(Sorry, I don't know Pylons, so I'll use a rails example - AFAIK, they should be close enough to prove my point)

The way I see it, there are two different model setups you could have

user <= has many => collections <= has many => items

or

user <= has many => collections
user <= has many => items
collections <= has many => items

If the collections belongs to the user, the user part of that URL is redundant because for a given collection, you can infer the user.

If the item belongs to the user, the collection is redundant, because you can infer the collection from the item.

Most of the time the models can be simplified down to this level.

Simon Wittber said...

If the collections belongs to the user, the user part of that URL is redundant because for a given collection, you can infer the user.

I would agree, however this requires each collection being accessed using its unique id number. I prefer to expose the collection name (which is only unique to the user, not unique across all collections), rather than a unique number in the URL. Because of this, my collections must be filtered by user.

garylinux said...

Try looking at Selector at http://lukearno.com/projects/selector/
I think it does what you are looking for.

gaspode said...

Ah, yes, the parent_resource option won't let you specify multiple parents at the moment.

However, you can still have a nested resource in the way you believe you can't. The parent_resource is actually just a shortcut that sets the path and name prefix options for you, note the changeset that added this feature and what it does.

If you add a path prefix with the additional variables it should retain for you, and your desired name prefix, you should be set.

dperezrada said...

I made the following:
- Add this line to Routing.py: map.connect('/users/:user_name/collections/:collection_name/items/:item_name', controller="users", action="show_item")
- Add the action to users controller:
def show_item(self, user_name, collection_name, item_name):
return Response('User: %s Collection: %s Item: %s' % (user_name, collection_name, item_name))
- Access to http://localhost:5000/users/myUserName/collections/myCollection/items/myItemName and you will see: User: myUserName Collection: myCollection Item: myItemName

I dont know if this resolve your problem.

Popular Posts