LOL Verbs and Gripes in URIs, Again

I may (or may not) get included in a project that’s defining a RESTful interface to an existing system. Most of it is really, really good. But then they lapse into the verb-in-the-URL anti-pattern:

POST http://host/something/v1/thingie/{id}/lock

POST http://host/something/v1/thingie/{id}/unlock

POST http://host/something/v1/thingie/{id}/publish

POST http://host/something/v1/thingie/{id}/unpublish

Here are some alternate approaches that are more RESTful. BTW I’m just talking to hear myself talk; this is covered much better in other forums.

Use a processor noun

I read about this (again) on the Interwebs, and it seems like the answer people are moving toward is changing the verb to a noun, and passing the desired state in the body with PUT. So

PUT http://host/something/v1/thingie/locker

{ id:{id}; lock:true }

PUT http://host/something/v1/thingie/publisher

{ id:{id}; publish:true }

Wait … PUT is idempotent. Is this? Well, if I lock a thing once, I’d expect that I could send 1000 PUTs and the end result would be: it is locked. Same for published and unpublished. Send 1000 publish:true, and it is published. Win!

EDIT: whoops… I don’t think this example is quite right. I’ve taken the verb, changed it to a noun, and then invoked it like a verb. It might be OK if you use POST, in the same way that “collection” nouns work. The next section is OK, though.

Use the factory variant

Alternately, you can treat it as a dedicated processor and put the id in the URI:

PUT http://host/something/v1/thingie/locker/{id}

{ lock:true }

PUT http://host/something/v1/thingie/publisher/{id}

{ publish:true }

Use POST and a virtual property

An even better solution would be to treat locked and published as properties of the resource. So

POST http://host/something/v1/thingie/{id}

{ locked:true; }

POST http://host/something/v1/thingie/{id}

{ published:true; }

Now I don’t need extra URIs at all! I can just use the resource URI and say, “Make it locked! Make it published!” Even if locked or published isn’t really a property of the underlying data in the database, you can still treat it as a property of that resource.

But…

This might not always be the best fit. For example, maybe “publishing” is more of a process than a property, and sending a “publish” command kicks of a series of actions, rather than just flipping a bit in the database. You might want to POST with the “processor” semantics, to make it clear that when you POST a request to the publisher, you’re explicitly kicking off some action, rather than just implying & hoping that some work is going to be done. Also, if PUT PUT PUT will generate a ton of work downstream for each PUT, you could argue it’s not really idempotent. Then you need POST POST POST.

Also, if there are properties of the request above what you’d be comfortable putting in the resource representation, then the processor looks attractive.

PUT http://host/something/v1/thingie/publisher/{id}

{ publish:true;
start:2011-01-30T12:00:00Z;
notify:false;
blackout:true;
replicate:false; }

Putting stuff at the end

As a minor gripe, I still hate tacking descriptors to the end of the URI, even if it’s still a noun. I like putting the static, non-changing stuff up front. That makes it a lot easier to parse, and removes namespace collisions, because you basically partition the URI into “type” and “identifier” portions. The type portion is just a static string for a resource type, and the identifier portion will change with each instance of that resource.

Blah:

POST http://host/something/v1/thingie/{id}/firstpiece

Yay:

POST http://host/something/v1/thingie/firstpiece/{id}

Or even less ambiguous:

POST http://host/something/v1/thingie-firstpiece/{id}

Or use the query string to narrow the request:

POST http://host/something/v1/thingie/{id}?piece=first

Stupid URIs

For example, these urls can collide and create parsing headaches:

http://somewhere/customer/firstname/john/lastname/reid

…you’re making “firstname” a reserved word, and knocking it out of your possible data values. Here that’s not a problem, but when you’re dealing with more abstract computer resources, it could be. Plus, I now have to parse the firstname, look at it, and decide what I need to parse next.

As opposed to

http://somewhere/customer/john/reid

or

http://somewhere/customer-by-name/john/reid

Now I can just split everything at / and I just know where everything is.

The problem is that you can very simply treat the URI as a tuple, and use the natural place notation to understand the meaning of each value. Or you can treat the URI as a sort of structured dictionary where the different place values have different meaning depending on what reserved words appear before them. Blech. I like simple.

The thing is….

Almost everyone is using some sort of a pattern-based framework for REST anyway. And I see people going to huge lengths to support redundant, wordy, and ambiguous URI definitions, when they could just define their URIs easily with a simple pattern. It’s like the old days when we used to argue about the XML representation of an object that we were going to put on the wire. Should we use elements or attributes? Who cares!? As long as the other side can parse it easily, just do whatever is easiest.

From a practical point of view, there’s no difference between

.../thingie/list

and

.../thingie-list

So why do we need to add ambiguity by making it heirarchical with “/” instead of just treating is as a single identifier? Really, seriously, why? Artistic reasons?

LOL OK what’s the point of having a blog if I don’t use it to spout off and restate the obvious? It’s not like you paid to get here, after all.

Advertisements

3 Comments

Filed under opinionizing, REST

3 responses to “LOL Verbs and Gripes in URIs, Again

  1. Pingback: Scott Banwart's Blog » Blog Archive » Distributed Weekly 85

  2. Phil

    For the lock example, could you use

    PUT http://host/something/v1/thingie/lock

    and to remove the lock

    DELETE http://host/something/v1/thingie/lock

    To check if a resource is locked, you try and fetch the lock, getting a 404 back if it isn’t there.

    • roby2358

      lol you’re absolutely right — “lock” is a funny case where the word is both a noun and a verb.

      I was trying to think of some riff on that, given the tendency in modern times to treat nouns as verbs. For example, does

      POST http://myhouse/party

      …violate REST or not? 😉

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s