Custom URL styles with CatalystX::CRUD

A recurring discussion in the Catalyst community revolves around best practices for URL construction. The Chained feature can make URLs fun (and so elegant!) to construct in your Controller code. But what should they look like to the user?

RESTful CRUD URLs are an increasingly common (and therefore contentious) practice. What's the proper way to create, read, update, and delete your precious data?

CatalystX::CRUD offers two different URL styles out-of-the-box. The RPC-style looks like:

 /user/list          # browse all users
 /user/search        # search for specific users
 /user/create        # create a user
 /user/joe/view      # read joe
 /user/joe/edit      # edit joe
 /user/joe/save      # update joe
 /user/joe/delete    # delete joe

The REST-style looks like:

 /user/list          # browse all users
 /user/search        # search for specific users
 /user/create_form   # create a user
 /user/joe           # GET joe
 /user/joe/edit_form # edit joe
 /user/joe           # PUT/POST joe
 /user/joe           # DELETE joe

The CatalystX::CRUD::REST Controller offers an RPC-compat config option as well, so that either style works.

But the special reserved method names in the Controllers mean that you can't have a user named search, create, or list. And that seems to rankle some folks, who would prefer a URL convention like:

 /user/id/joe        # GET joe
 /user/id/joe/save   # POST joe

With the extra /id in there, there are no reserved words when dealing with user instances. Cleaner, yes, at the expense of a little URL length.

Here's a quick way to customize your CatalystX::CRUD instance URLs to add that extra /id (or whatever) into your URLs to appease your sense of URL correctness.

The PathPrefix hack was first introduced by Brian Cassidy, who deserves mad props for his simple genius. The effect is to make your initial Chained starting method match the namespace of the current controller, so that you can move your controllers around and not have to rewrite any code (which is what makes CatalystX::CRUD::Controller subclasses work). The original looks like:

 sub _parse_PathPrefix_attr {
    my ( $self, $c, $name, $value ) = @_;
    return PathPart => $self->path_prefix;

Override _parse_PathPrefix_attr() in your controller and you can append whatever you want to the path_prefix() to get the desired effect:

 sub _parse_PathPrefix_attr {
    my ( $self, $c, $name, $value ) = @_;
    return PathPart => $self->path_prefix . '/id';

That's it.

Happy CRUD!


Peter 'karpet' Karman karman at