Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I'am planning to build RESTfull API but there are some architectural questions that are creating some problems in my head. Adding backend bussiness logic to clients is option that I would like to avoid since updating multiple client platforms is hard to maintain in real time when bussiness logic can rapidly change.

Lets say we have article as a resource ( api/article ), how should we implement actions like publish, unpublish,activate or deactivate and so on but to try to keep it as simple as possible?

1) Should we use api/article/{id}/{action} since a lot of backend logic can happen there like pushing to remote locations or change of multiple properties. Probably the hardest thing here is that we need to send all article data back to API for updating and multiuser work could not be implemented. For instance editor could send 5 seconds older data and overwrite fix that some other journalist just did 2 seconds ago and there is no way that I could explain to clients this since those publishing an article is really not in any way connected to updating the content.

2) Creating new resource can also be an option, api/article-{action}/id , but then returned resource would not be article-{action} but article which I'am not sure if this is proper. Also in server side code article class is handling actuall work on both resource and I'm not sure if this goes against RESTfull thinking

Any suggestions are welcomed..

share|improve this question
    
It's perfectly legal to have 'actions' be part of a RESTful URI - if they state an action/algorithm to be performed. What's wrong with api/article?action=publish? Query parameters are intended for such cases where the state of the resource is dependent on the 'algorithm' (or action) you mention. E.g. api/articles?sort=asc is valid –  PhD Mar 26 '12 at 1:58
1  
I suggest you check out this write-up, which may inspire you with an even more RESTful solution. –  Benjol Mar 26 '12 at 9:55
    
One of problems I see with api/article?action=publish is that in RESTfull application should send ALL article data for publishing while I would prefer to do just this: api/article/4545/publish/ without anything additional –  Miro Svrtan Mar 30 '12 at 20:38

5 Answers 5

Operations resulting in major state and behavior changes on the server side like the "publish" action you describe are difficult to model explicitly in REST. A solution I often see is to drive such complex behavior implicitly through data.

Consider ordering goods through a REST API exposed by an online merchant. Ordering is a complex operation. Several products will be packaged and shipped, your account will be charged, and you'll get a receipt. You can cancel your order for a limited amount of time and there is of course a full money back guarantee which allows you to send back products for a refund.

Instead of a complex purchase operation, such an API might allow you to create a new resource, a purchase order. At the beginning you can make any modifications you wish to it: add or remove products, change shipping address, choose another payment option, or cancel your order altogether. You can do all of these because you have not bought anything yet, you are just manipulating some data on the server.

Once your purchase order is complete and your grace period passes, the server locks your order to prevent any further changes. Only at this time the complex sequence of operations starts, but you cannot control it directly, only indirectly through the data you placed previously into the purchase order.

Based on your description, "publish" could be implemented in this fashion. Instead of exposing an operation, you place a copy of the draft you've reviewed and want to publish as a new resource under /publish. This guarantees the any subsequent updates to the draft won't be published even if the publish operation itself completes hours later.

share|improve this answer
    
The idea of changing the whole resource from unpublished article to draft would fit exactly this case but wouldnt fit all other actions that exist on a resource in general. Is REST even supposed to handle it? Maybe I'm abusing it and should only use it as CRUD and nothing more, like SQL queries where I dont expect any logic to be inside the query itself. –  Miro Svrtan Mar 25 '12 at 20:34
    
Why I'm asking all of this? Well since some time ago web apps start to be multiplatformed and I would prefer to keep a lot of bussines logic on the server since updating bussiness logic on iOS,Android,web,desktop or whatever other platform comes to mind is getting pretty impossible to do quickly and I would like to avoid all problems of backwards compatibility when changing some small piece of BL. –  Miro Svrtan Mar 25 '12 at 20:39
1  
I think REST can handle business logic just fine, but it is not that suitable for exposing existing business logic written without having REST in mind. This is why many companies like Microsoft, SAP, and others often expose only data with CRUD operations, just like you said. Have a look ad the Open data Protocol to see how they do it. –  Ferenc Mihaly Mar 25 '12 at 21:51

we need to send all article data back to API for updating and multiuser work could not be implemented. For instance editor could send 5 seconds older data and overwrite fix that some other journalist just did 2 seconds ago and there is no way that I could explain to clients this since those publishing an article is really not in any way connected to updating the content.

This sort of thing is a challenge no matter what you do, It's a very similar problem to distributed source control (mercurial, git, etc.), and the solution, spelled in HTTP/ReST, looks a bit similar.

Supposing you've got two users, Alice and Bob, both working on /articles/lunch. (for clarity, response is in bold face)

First, alice creates the article.

PUT /articles/lunch HTTP/1.1
Host: example.com
Content-Type: text/plain
Authorization: Basic YWxpY2U6c2VjcmV0

Hey Bob, what do you want for lunch today?

301 Moved Permanently
Location: /articles/lunch/1 

The server did not create a resource, because there was no "version" attached to the request, (assuming an identifier of /articles/{id}/{version}. To perform the creation, Alice was redirected to the url of the article/version she'll be creating. Alice's user agent will then reapply the request at the new address.

PUT /articles/lunch/1 HTTP/1.1
Host: example.com
Content-Type: text/plain
Authorization: Basic YWxpY2U6c2VjcmV0

Hey Bob, what do you want for lunch today?

201 Created

And now the article has been created. next, bob looks at the article:

GET /articles/lunch HTTP/1.1
Host: example.com
Authorization: Basic Ym9iOnBhc3N3b3Jk

301 Moved Permanently
Location: /articles/lunch/1 

Bob looks there:

GET /articles/lunch/1 HTTP/1.1
Host: example.com
Authorization: Basic Ym9iOnBhc3N3b3Jk

200 Ok
Content-Type: text/plain

Hey Bob, what do you want for lunch today?

He decides to add his own change.

PUT /articles/lunch/1 HTTP/1.1
Host: example.com
Content-Type: text/plain
Authorization: Basic Ym9iOnBhc3N3b3Jk

Hey Bob, what do you want for lunch today?
Does pizza sound good to you, Alice?

301 Moved Permanently
Location: /articles/lunch/2

As with Alice, Bob is redirected to where he will be creating a new version.

PUT /articles/lunch/2 HTTP/1.1
Host: example.com
Content-Type: text/plain
Authorization: Basic Ym9iOnBhc3N3b3Jk

Hey Bob, what do you want for lunch today?
Does pizza sound good to you, Alice?

201 Created

Finally, Alice decides that she would like to add to her own article:

PUT /articles/lunch/1 HTTP/1.1
Host: example.com
Content-Type: text/plain
Authorization: Basic YWxpY2U6c2VjcmV0

Hey Bob, what do you want for lunch today?
I was thinking about getting Sushi.

409 Conflict
Location: /articles/lunch/3
Content-Type: text/diff

---/articles/lunch/2
+++/articles/lunch/3
@@ 1,2 1,2 @@
 Hey Bob, what do you want for lunch today?
-Does pizza sound good to you, Alice?
+I was thinking about getting Sushi.

Instead of being redirected as normal, a different status code is returned to the client, 409, which tells Alice that the version she was trying to branch from has already been branched. The new resources was created anyways (as shown by the Location header), and the differences between the two was included in the response body. Alice now knows that the request she just made needs to be merged some how.


All of this redirection is related to the semantics of PUT, which requires that new resources be created exactly where the request line asks. this could also save a request cycle using POST instead, but then the version number would have to be encoded in the request by some other magic, which seemed less obvious to me for the purposes of illustration, but would probably still be preferred in a real API to minimize request/response cycles.

share|improve this answer
    
Versoning was not an issue here, I just said it as example of possible problems if using article as a resource for publishing action –  Miro Svrtan Mar 25 '12 at 20:18

REST is data oriented and as such resources work best as "things" not actions. The implicit semantics of http methods; GET, PUT, DELETE, etc serve to reinforce the orientation. POST of course, is the exception.

A resource can be a mixture of data ie. article content; and metadata ie. published, locked, revision. There are many other possible ways to slice up the data, but you have to go through the what the data flow will look like first in order to determine the most optimal one (if there is one). For example it may be that revisions should be their own resource under the article as TokenMacGuy suggests.

Regarding implementation I would probably do something like what TockenMacGuy suggests. I would also add a metadata fields on article, not revision, like 'locked' and 'published'.

share|improve this answer

Here's another example that deals not with documents content but more with transient state. (I find versioning -- given that, in general, each version can be a new resource -- a kind of easy problem.)

Let's say I want to expose a service running on a machine via a REST so that it can be stopped, started, restarted, and so forth.

What is the most RESTful approach here? POST /service?command=restart, for example? Or POST /service/state with a body of, say, 'running'?

It'd be nice to codify best practices here and whether REST is the right approach this type of situation.

Second, let's assume I want to drive some action from a service that doesn't affect its own state, but rather triggers a side effect. For example, a mailer service that sends out a report, built at the time of call, to a bunch of emails addresses.

GET /report might be a way of getting a copy of the report myself; but what if we want to push to the server side further actions such as emailing as I say above. Or writing to a database.

These cases dance around resource-action divide, and I see ways of handling them in a REST-oriented manner, but frankly it feels a like a bit of a hack to do so. Perhaps the key question is whether a REST API should support side-effects in general.

share|improve this answer

If I understand you correctly, I think that what you have is a more of a 'business rule' determination issue than a technical issue.

The fact that an article can be overwritten could be resolved by introducing authorization levels where senior users can override junior user's versions.Also by introducing versions as well as a column to capture the state of the article (e.g. 'in development', 'final', etc.), you could overcome this. You also may give the user the ability to select a given version either by a combination of time of submission and by the version number.

In all of the above cases, your service need to implement the business rules you set. So you could call the service with the parameters: userid, article, version, action (where the version is optional, again this depends on your business rules).

share|improve this answer
    
I dont belive that this is a bussiness rule but strictly a techincal one. The idea with adding version is a good one to help with overriding rules but still doesnt solve situation that updating content and publishing content are not related actions. –  Miro Svrtan Mar 25 '12 at 12:58

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.