Sunday, June 15, 2014

Revisiting the Design of Restful Service API's

As part of an on going side project, I've been building a couple of services into a web site that handles images provided by guests of the application.  For production we need to manage these images, involving cleaning them up and optimizing them for delivery to the presentation.

First during the upload service we will need to prepare the image for handling by the application.  Then during viewing the service layer will needs to provide different renderings of the image as required by the application presentation.

Subsequently the application will need a image service to provide this functionality.  This image service will need to allow the presentation layer of the image to request the size of the image.  Also in production it is almost certain that this service will be cached.

So the question arose what is the best practice for handling service arguments for RESTful services?  In our example here we have three arguments; the id of the image along with the width and height of the image.  With the id argument the decision is straight forward, it should be part of the URL.  However with the width and height arguments things are not so simple. Should it be a query parameter or a path segment in the URL?

There are pluses and minus's to either route.  Putting path segments in the URL presents problems when arguments are optional.  The nature of the services response changes for handling missing results depends also on how the argument is passed. When passing arguments as a path segment the service should return a 404 status, while with query parameters and empty result set should be returned.

This in turn leads to the question of 'What are the best practices for determining how to send service arguments to the service layer of the application'?

While seeking that answer I ran across this on Stacktrace.  This is a great response in the sense that it provides a framework for determining how data is passed to the service layer given the type of data.

Late answer but I'll add some additional insight to what has been shared, namely that there are several types of "parameters" to a request, and you should take this into account.
  1. Locators - E.g. resource identifiers such as IDs or action/view
  1. Filters - E.g. parameters that provide a search for, sorting or narrow down the set of results.
  1. State - E.g. session identification, api keys, whatevs.
  1. Content - E.g. data to be stored.
Now let's look at the different places where these parameters could go. 
  1. Request headers & cookies
  1. URL query string ("GET" vars)
  1. URL paths
  1. Body query string/multipart ("POST" vars)
Generally you want State to be set in headers or cookies, depending on what type of state information it is. I think we can all agree on this. Use custom http headers (X-My-Header) if you need to. 
Similarly, Content only has one place to belong, which is in the request body, either as query strings or as http multipart and/or JSON content. This is consistent with what you receive from the server when it sends you content. So you shouldn't be rude and do it differently. 
Locators such as "id=5" or "action=refresh" or "page=2" would make sense to have as a URL path, such as where partly you know what each part is supposed to mean (the basics such as article and 5 obviously mean get me the data of type article with id 5) and additional parameters are specified as part of the URI. They can be in the form of page=2, or page/2 if you know that after a certain point in the URI the "folders" are paired key-values. 
Filters always go in the query string, because while they are a part of finding the right data, they are only there to return a subset or modification of what the Locators return alone. The search in (subset) is a filter, and so is /article/5?order=backwards(modification). Think about what it does, not just what it's called! 
If "view" determines output format, then it is a filter ( because it returns a modification of the found resource rather than homing in on which resource we want. If it instead decides which specific part of the article we get to see ( then it is a locator. 
Remember, narrowing down a set of resources is filtering. Locating something specific within a resource is locating... duh. Subset filtering may return any number of results (even 0). Locating will always find that specific instance of something (if it exists). Modification filtering will return the same data as the locator, except modified (if such a modification is allowed). 
Hope this helped give people some eureka moments if they've been lost about where to put stuff!

Here is the link to the original page;


No comments:

Post a Comment