Rest Non-Crud

Often, REST interfaces can be seen as basic CRUD interfaces, and the pattern is so strong that sometimes it’s difficult to see how to use REST for things other than CRUD. In this post I’ll discuss how to issue commands against resources.

Rest Command Pattern

Problem

Given an object, ask the rest server to perform a non-crud operation on it.

Example

My user wants to submit an order, but all orders must be approved before processing.

Naive Design:

The client could change the order’s status field and issue a PUT to the service sending back a complete copy of the order. The server could use the resource uri to load the order and compare it to the order sent from the client. It will discover that the status field has changed and infer the correct command from its value.

The reason this is naive is that in any non-trivial application the object graph representing the order may be large and complex, and navigating through it to the correct status indicator may be a chore. Also, you may not actually want the client changing the status, or even sending that field across the wire. If the client changes the status to ‘approved’ and then the PUT fails, then it has to change it back again, which would mean that the server and client models are out of sync for a while — something that is quite undesirable.

This leads to a lot of code pulling apart the model looking for changes and trying to guess the appropriate command/action to take based on those changes. Even when you find a class of commands (‘approve’, ‘reject’) you end up with a string of ‘if’ statements which isn’t particularly OO: if(status == ‘approve’) then new ApproveCommand() else if (status == ‘reject’) then new RejectCommand()…

Also, it seems like a poor idea to try to infer the user’s intent from the data, as the client actually has this information — it just hasn’t communicated it clearly to the server.

Solution

The client should send extra information with the PUT to allow the server to route to the correct, specific, handler.

Implementation

There are three possible implementations

  1. Send the command as a query parameter: http://server/service/model/id?command=approve
  2. Send the command as part of the URI: http://server/service/model/approve/id or http://server/service/approve/model/id
  3. Send the command as part of the object being PUT: order.command=’approve’
  4. Send the command as a header parameter: headers : {command:’approve’}

Number one and two suffer from problems like cache busting (because the uri has appeared to change). The second solution adds an unnecessary name/value pair to the object which may break the service because the server may not be expecting it or may require extra code to deserialize, and then the code still has may if-statements based on the value of the command.

The final solution, using a header parameter, seems perfect. The resource isn’t infected with the command, the URI doesn’t change (and why should it — we’re operating on a resource, not changing which resource we’re using), and, at least in Spring, we can route to specific methods in our service implementation based on header values, rather than having lots of if-statements everywhere.

In Spring we can use header values as part of the router which is easily configured via annotations on the service implementation, so it’s easy to invoke a specific method based on a header value: @RequestMapping(header = “command=approve”, method=PUT).

Leave a Reply

Please log in using one of these methods to post your comment:

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