Alan Dean

CTO, Developer, Agile Practitioner

Photograph of Alan Dean

Friday, November 7, 2008

When Basket Checkout isn't RESTful

Following on from my twitter chat, here is why I think that the following two basket checkout styles are not RESTful.

GET /checkout

When the server keeps session state about a user basket (cart in the US) you will tend to see checkout as a regular GET. This is because the server keeps track of all the "Add to Basket" choices of the user. Somewhere, a token is being kept that links the user to the session state on the server; this may be a token in the URI, in a server cookie or in ViewState. Whichever method is chosen, the significant fact is that the server has knowledge of the application state of the client.

This is in breach of the hypermedia as the engine of application state (HATEOAS) constraint of REST. It also breaches the more general Uniform Interface constraint by failing to manipulate resources through the exchange of representations.

Let me be perfectly clear. This is effectively the standard pattern for implementing basket and checkout across the whole of web. It is perfectly valid as an architectural style: it is simply not RESTful, that's all.

Content-Type: text/uri-list

During the twitter chat, serialseb proposed an alternative approach whereby a 'personalized resource' of the user basket is hosted somewhere. In one version, this can be RESTful (see next blog post) but in another, it isn't.

If the client sends a message (where the provided link is a representation of the basket state):

POST /checkout
Content-Type: text/uri-list

http://example.com/username/basket

Then I don't consider this to be RESTful either because there is no representation being exchanged with the server by the client.

Again, to be clear, it's perfectly valid HTTP - it's just not REST.

In addition to the non-RESTfulness of the style, it has a couple of 'difficulties':

  1. Which Content-Type should the server Accept from the provided URI?
  2. The application state is inherently confusing. Should the server check if the basket is updated? If it does update, should the server change the order? To the original implementers of such a system, no doubt the answer is obvious but later implementers may not find life so easy. An example of this kind of problem can be seen with OpenID where sites tend to work with a select set of OpenID providers but break with others.
  3. Access Control:
    • Does the URI provided require authentication? If not, private data is available for anyone to view. If so, how does the server hosting the checkout obtain the credentials?
    • How is the server hosting the checkout granted authorization to read the basket state?

These problems can clearly be overcome. For example, by complex redirects such as we see with credit card authorization today but the complexity is unnecessary and typically ends up with a situation of bespoke systems integration.

In short, this is another breach of the hypermedia as the engine of application state (HATEOAS) constraint of REST.

Finally, because of the lack of RESTfulness I consider that neither of these options are serendipitous.

P.S.

I forgot to state that the second example also breaches the Layered System constraint because the server has knowledge of the client persistence store. In my following post I discuss using a 'personalized resource' in a RESTful way.

5 comments:

Sebastien Lambla said...

Started writing a long comment, but it can be summed up as:

Is the uri identifying a resource a valid representation of such resource?

text/uri-list is a valid representation of a uri. And webarch doesn't help us much for this:

A representation is data that encodes information about resource state.

What happens when the uri (or uri-list) is received by the server? If we accept that such representation is indeed valid for our resource, then the server can attempt to dereference that uri, a process that would be by definition very quick in the situation where it issued such uri itself.

Is it reasonable for the server to reply that it is a client error to send a Uri not issued by that server? Woudl it still be restful? Backtracking the questions that arised around amazon s3's use of copy may be of interest.

Alan Dean said...

What I should also have mentioned is that it breaches the Layered System constraint (because the server has knowledge of the client persistence store). In the next post I discuss the use of a 'personalized resource' which doesn't breach this constraint.

Colin Jack said...

"Somewhere, a token is being kept that links the user to the session state on the server"

Is this always session state though?

If I look at Amazon my basket has real meaning, I can add things to it, go away for 6 months and come back and they are still there.

Could this not be seen as making the basket a really meaningful resource in its own right?

"Then I don't consider this to be RESTful either because there is no representation being exchanged with the server by the client."

Just thinking of Amazon, from the point where you submit your basket there are multiple POSTs before you complete the request. Along the way you specify multiple values (resources?) such as address details, whether to gift wrap (and other misc) to payment details.

Thinking of designing RESTful WS around this I'd be considering having you submit (PUT) one OrderPlacementInformation resource (no idea on terminology) which had those details and reference to the basket.

The result would be the creation of all sorts of other resources and in particular an Order, we would also update existing resources such as the basket itself.

Just an idea, be interested in your views.

Alan Dean said...

Colin,

I suspect that you are missing the point that I am making, that "Somewhere, a token is being kept that links the user to the session state on the server". The token is not the important part. It is the link to session state on the server that is the problem.

In the next post "What a RESTful Basket Checkout might look like", I discuss this issue. The example I refer to is "You might, for example, have requirement to remember the last basket state in order to highlight previous purchases." but basket persistence across a period of 6 months is equally valid.

I have no problem with the basket data being kept on a server. The problem is keeping it in session within the context of the 'checkout application'.

Sounds like I need to write another post to drive into this in more detail. I'll try to put that together this afternoon for you.

Alan Dean said...

Colin,

I have just posted "On RESTful Basket State" which will hopefully cast more light on your question.