RESTBucks Evolved
The book REST in Practice: Hypermedia and Systems Architecture uses an imaginary StarBucks-like company as its running example.
I think this is a great example, since most people are familiar with the domain.
The design is also simple enough to follow, yet complex enough to be interesting.
Problem Domain
RESTbucks is about ordering and paying for coffee (or tea) and food. Here is the state diagram for the client:
- Create the order
- Update the order
- Cancel the order
- Pay for the order
- Wait for the order to be prepared
- Take the order
Book Design
The hypermedia design in the book for the service is as follows:
- The client
POST
s an order to the well-known RESTBucks URI. This returns the order URI in theLocation
header. The client thenGET
s the order URI - The client
POST
s an updated order to the order URI - The client
DELETE
s the order URI - The client
PUT
s a payment to the URI found by looking up a link with relationhttp://relations.restbucks.com/payment
- The client
GET
s the order URI until the state changes - The client
DELETE
s the URI found by looking up a link with relationhttp://relations.restbucks.com/receipt
The book uses the specialized media type application/vnd.restbucks.order+xml
for all messages exchanged.
Design Problems
Here are some of the problems that I have with the above approach:
- I think the well-known URI for the service (what Mike Amundsen calls the billboard URI) should respond to a
GET
, so that clients can safely explore it.
This adds an extra message, but it also makes it possible to expand the service with additional functionality. For instance, when menus are added in a later chapter of the book, a second well-known URI is introduced. With a proper home document-like resource in front of the order service, this could have been limited to a new link relation. - I’d rather use
PUT
for updating an order, since that is an idempotent method. The book states that the representation returned byGET
contains links and argues that this implies that (1)PUT
messages should also contain those links and (2) that that would be strange since those links are under control of the server.
I disagree with both statements. A server doesn’t necessarily have to make the formats forGET
andPUT
exactly the same. Even if it did, some parts, like the links, could be optional. Furthermore, there is no reason the server couldn’t accept and ignore the links. - The
DELETE
is fine.
An alternative is to usePUT
with a status ofcanceled
, since we already have a status property anyway. That opens up some more possibilities, like re-instating a canceled order, but also introduces issues like garbage collection. - I don’t think
PUT
is the correct method. Can the service really guarantee under all circumstances that my credit card won’t get charged twice if I repeat the payment?
More importantly, this design assumes that payments are always for the whole order. That may seem logical at first, but once the book introduces vouchers that logic evaporates. If I have a voucher for a free coffee, then I still have to pay for anything to eat or for a second coffee.
I’d create a collection of payments that the client shouldPOST
to. I’d also use the standardpayment
link relation defined in RFC 5988. - This is fine.
- This makes no sense to me: taking the order is not the same as deleting the receipt. I need the receipt when I’m on a business trip, so I can get reimbursed!
I’d ratherPUT
a new order with statustaken
.
Service Evolution
Suppose you’ve implemented your own service based on the design in the book.
Further suppose that after reading the above, you want to change your service.
How can you do that without breaking any clients that may be out there?
After all, isn’t that what proponents tout as one of the advantages of a RESTful approach?
Well, yes and no. The media type defined in the book is at level 3a, and so will allow you to change URIs. However, the use of HTTP methods is defined out-of-band and you can’t easily change that.
Now imagine that the book would have used a full hypermedia type (level 3b) instead. In that case, the HTTP method used would be part of the message. The client would have to discover it, and the server could easily change it without fear of breaking clients.
Of course, this comes at the cost of having to build more logic into the client. That’s why I think it’s a good idea to use an existing full hypermedia type like Mason, Siren, or UBER. Such generic media types are much more likely to come with libraries that will handle this sort of work for the client.
Reference: | RESTBucks Evolved from our JCG partner Remon Sinnema at the Secure Software Development blog. |