

The S in Rest - fishtoaster
http://teddziuba.github.io/2014/08/18/the-s-in-rest/

======
frederickf
"I propose that we use use existing REST semantics for indicating state"

But there are no REST semantics for indicating state. REST is stateless:
[http://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch...](http://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm#sec_5_1_3).
I think maybe he's conflating HTTP with REST.

This problem could be solved in a RESTful way by returning a resource that
includes all the needed information. I understand he describes that as not
being robust, but that doesn't mean it isn't RESTful. In fact fielding
acknowledges this very trade-off:

"Like most architectural choices, the stateless constraint reflects a design
trade-off. The disadvantage is that it may decrease network performance by
increasing the repetitive data (per-interaction overhead) sent in a series of
requests, since that data cannot be left on the server in a shared context."

Also, because REVAT URLs are randomly generated the server needs keep track of
the resources being pointed to instead of being able to understand it from the
semantics of the request. Which works fine right up until you have to scale
your application to more than one server. Now you have to deal with the
complexity of keeping a distributed system consistent - otherwise those REVAT
URLs might sometimes return a 404 - or you're limited to a single centralized
link server. These are both scenarios Fielding was trying to avoid by
including statelessness as a constraint.

~~~
steego
> Also, because REVAT URLs are randomly generated the server needs keep track
> of the resources being pointed to instead of being able to understand it
> from the semantics of the request.

This is where he lost me. If you need to generate unique URL's, why not go for
a hash approach ala git?

------
jonahx
The problem described isn't a technology problem. It's a business domain
problem, and it should be solved by fixing the domain modeling. The example
doesn't uncover any problems with REST architecture.

If prices are changing and you need to capture them, the "Product" concept
isn't enough. You need to model the concept of price, and perhaps price change
events too. So a customer doesn't buy a product, but a product together with a
"ProductPrice".

~~~
jdmichal
I generally don't understand the example. An "Invoice" object should capture
everything relevant to the purchase, including prices, taxes, shipping, etc.
Identifying a "Product" via ID is fine, and that Product may even have a
"current price" attached to it. But in no way should that referenced Product
object impact the captured Invoice object.

~~~
johnwalker
Coming up with names for groups of data that you want to be atomic isn't that
useful, though.

~~~
jdmichal
I don't understand. That's exactly what domain modeling is. Putting names to
the data you need to store and, in this case, capture at a particular moment
in time.

Let's put it this way. Do you think it is reasonable to store the taxes as a
reference, or the shipping cost? We would never consider it appropriate to
say, "Go look up the shipping cost for a 5lb package from here to here." Oh,
and by the way, this is using a live reference to a customer object, for which
the shipping address might very well have changed.

Of course we would not do this. So why would it appropriate for a product
price? An invoice _is_ the capture of all this information at the moment the
purchase is made. That is its purpose. If we did not need this moment-in-time
capture, then the concept of an invoice would not even exist.

------
bcoates
This does not seem like a reasonable idea in a business-rules sense. the 12345
in
[http://api.example.com/product/12345](http://api.example.com/product/12345)
is presumably a SKU, which is the natural key for a product you're selling.
You don't get to convert it into a GUID and declare it immutable.

If the price isn't effectively fixed, the API client is going to need to
generate a quote ('shopping cart'). The API rates the product when the quote
is made, and then there is some business rule about how to handle quotes from
before the price change.

The value-based URL refers to an entity ('SKU-price pair from some time in the
past') which has no reasonable use.

~~~
aphelion
So generate immutable ProductState objects that contain all parts of the
domain model that can change over time, and maintain a mapping from SKU to the
correct object.

So GET /product/12345 returns UUID_1 at time A, when details of the offered
item change at time B a UUID_2 gets generated and a new GET /product/12345
returns UUID_2.

If you want to be really anal retentive, generate the product state objects
with timestamps to compare to the Date header in requests and have a list of
product states that have been referenced by a given SKU to traverse through to
get correct product details even when the catalog changes between sending and
receipt of the request.

~~~
SilasX
>So generate immutable ProductState objects that contain all parts of the
domain model that can change over time, and maintain a mapping from SKU to the
correct object.

But that just recreates the very problem the author set out to solve, which is
that you have to send increasingly huge sub graphs of the database with each
order.

I assumed the direction he was going to go was to let the client send the at-
the-time data back with each subsequent request for time consistency, but
require them to pass a server-provided signature to keep them from making up
prices, and saving the server from having to keep a time history of every
case.

------
Mister_Snuggles
These problems are similar to the normalization problems that occur when
designing a database.

If you have tables such as Orders, OrderItems, and Items, you need to account
for the attributes of Items changing over time and how that will affect past
Orders. The problems are potentially bigger in REST, but they're not
necessarily new problems.

The Cost of Goods Sold problem, in particular, has already been solved in a
couple of different ways by the accounting profession. See
[http://en.wikipedia.org/wiki/Cost_of_goods_sold#Identificati...](http://en.wikipedia.org/wiki/Cost_of_goods_sold#Identification_conventions)
for some details.

------
elchief
Return customer and product in same HTTP response?

Also, that's not how sales orders work. A sales order is a commitment to
provide a product at a price at a time to a party. The price is tied to the
order. If the price of the product changes, that does not affect the order.

------
gioele
Memento the "HTTP Framework for Time-Based Access to Resource States" [0,1]
tries to approach the "time" problem of REST with an additional set of headers
and intermediate gate-keepers.

See [http://www.mementoweb.org/guide/quick-
intro/](http://www.mementoweb.org/guide/quick-intro/) for an introduction.

[0] RFC 7089 (Informational) [1]
[http://mementoweb.org](http://mementoweb.org)

------
glennericksen
Arguably, you could the fix OP's issue by improving/changing the domain model.
In this example, issue of state arises because the Order relies on the
inherent possibility of changes to the attributes of a Product. Adding line
items(quantity,price,product_id,etc) instead of direct product associations
would provide a more stable representation that's easy to reason about without
the additional complexity of REVAT.

------
joeframbach
As an example alternative, Mongoose has versioning in its schemas. If you GET
/product/12345, you'll receive the product info, along with its revision
number, let's say this is revision 3. The user decides to buy the product, so
they POST /orders with {productId:12345, __v: 3}. In the meanwhile, the store
has updated the product, and Mongoose updates the revision to 4. Versions
mismatch, send a 409.
[http://aaronheckmann.tumblr.com/post/48943525537/mongoose-v3...](http://aaronheckmann.tumblr.com/post/48943525537/mongoose-v3-part-1-versioning)

------
hcarvalhoalves
So, separating your REST API into indexes and values effectively creates a
database over HTTP. This transfers complexity to the client though, which I
don't think is the point of having an API in the first place (you could just
give clients the login to your database).

~~~
discreteevent
The problem that I see with REST is that it leads in general to APIs that tend
to transfer logic to the client. This is basically a loss of encapsulation and
makes it harder to change the server implementation later without breaking
clients. It took a long time for the industry to move towards behavioural
interfaces for good reasons. Are those reasons now void? I know that there is
some encapsulation because only a representation is transferred but still,
REST interfaces tend to represent state and not behaviour. Am I wrong?

~~~
dragonwriter
> The problem that I see with REST is that it leads in general to APIs that
> tend to transfer logic to the client.

That's just bad API design -- specifically poorly chosen resources.

> I know that there is some encapsulation because only a representation is
> transferred but still, REST interfaces tend to represent state and not
> behaviour. Am I wrong?

They _by definition_ transfer the _state_ of a _resource_. So, in a trivial
sense, you are correct. Substantively, though, there is no reason an
individual REST resource couldn't be an instance of a behavior, or that state
modifications to a resource couldn't trigger modifications to many back-end
entities (and other front-end exposed resources.)

To use RDBMS languages, REST resources are often treated like base tables when
they _should be_ more like application-specific updateable views. This has
nothing to do with REST architecture, and everything to do with the fact that
domain modelling is harder than implementing an API, and yet (regardless of
the architecture chosen for the API) people often spend more effort on
implementing the API than designing the domain model.

~~~
discreteevent
Yes, getting a domain model right up front can be very hard. That's why
behavioural interfaces that hide as much as possible were found to be more
forgiving when we realise that we failed to predict the future correctly when
dreaming up V1 of the product. They make it easier to evolve.

------
pjungwir
I'm delighted to see a Ted Dziuba post! I'm very sad his posts criticizing
Node disappeared. I never decided whether I bought his argument, but I thought
they were valuable contributions to the discussion about the event-driven
model. They did not seem trollish to me but earnest, and I would have liked to
read a debate about them.

This REVAT post is also something I'd love to see get picked up and discussed
more. I certainly have felt the need for immutable values indicating a
snapshot of a thing's state. Personally I'd like to know how people solve this
at the RDBMS level more than the REST API level, but there's a need in both
places.

~~~
findjashua
To be fair, his argument against Node.js is applicable to any system with co-
operative scheduling (twisted, tornado, eventmachine, Go etc), and the only
way around it is pre-emptive scheduling (Erlang/Elixir, Haskell etc). Node has
a lot of problems, but co-operative scheduling is not one of the more
important ones.

------
skybrian
This is just another design decision. In git terms, linking to a particular
revision is sometimes useful. So is linking to HEAD. There's no domain-
independent rule that says you have to support both or prefer one or the
other, so long as you know what your customers need and don't get them
confused.

If you really want to link to a snapshot that can be downloaded later, using a
content hash like git or camlistore might be a good idea.

------
MichaelGG
Why does HTTP specify such odd stuff like "never expires" being 1 year in the
future, and "should not" send higher values. What does that tell a program to
do? Cause instead of defining some sort of sensical behaviour ("send a
thousand years as never"), you've got this odd scenario where never might be a
year. Or maybe you send 2 years, and clients act improperly.

It seems that whoever wrote this spec wasn't writing much software, and didn't
intent others to write software from the spec.

~~~
deathanatos
> Why does HTTP specify such odd stuff

It doesn't, at least anymore, though I agree it would've been good if they'd
specified some reasoning for that magical value. Granted it only changed in
June, but he's quoting an obsolete RFC. (And if you look up the RFC on the
IETF's website, the header color will indicate this, along with the "Obsoleted
by…") Currently that section¹ actually reads:

> Historically, HTTP required the Expires field-value to be no more than a
> year in the future. While longer freshness lifetimes are no longer
> prohibited, extremely large values have been demonstrated to cause problems
> (e.g., clock overflows due to use of 32-bit integers for time values), and
> many caches will evict a response far sooner than that.

Honestly, they could have just specified a "never" value, like the word
"never". That said, I'm not sure a forever resource would be a good idea: the
other side's cache would never empty, and honestly, I don't think I've ever
seen a piece of data that never changed, either because the spec did
eventually change, or the data was incorrect due to human error, etc.

Further, you can't really guarantee a response will be cached forever: caches
get cleared all the time for a variety of reasons. Cache to reduce load, not
to put some sort of new behavior in the system.

¹[http://tools.ietf.org/html/rfc7234#section-5.3](http://tools.ietf.org/html/rfc7234#section-5.3)

------
bumelant
I don't think this has strictly something to do with the state in REST. This
is about state of things changing in general.

What you can do about it (other than creating something along the lines of
your idea) is to create a history/snapshot on updates. I'm pretty sure most
languages/frameworks has something for that, in Java/JPA you can do this by
using Hibernate Envers' revisions. Exposing these revisions via REST API
pretty much is what you suggested.

------
Geee
Many people here doesn't seem to get what the author is talking about. If I
link to [http://www.google.com](http://www.google.com), the content might have
changed when you open it. The URL always references the state of the resource
at the time of retrieval, which is not always the intention. REVAT is just a
proposed way to reference a specific state of a resource.

~~~
notdonspaulding

        REVAT is just a proposed way to reference a specific state of a resource.
    

...at a specific point in time.

------
vdm
The Content-Location response header can carry the value URL without a
redirect.
[http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14...](http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.14)

With canonical representations (standardised whitespace and key sort order
etc) a hash can be used as a content-addressable key in place of a UUID.

------
batbomb

          There’s a consistency problem: the price may have
          changed  between the time that we received the order 
          and the time we looked up the product. To patch it up,
          we attach the product price to the order:
    
    

What you are describing is the lost update problem. This is solved in several
ways. For example, an If-Unmodified-Since or If-Match header. In the first
POST method, you had to get the product ID from somewhere, so you might have
obtained a date or etag representing that product at a specific point in time.

When you POST the order, you could put the date of the last time you saw the
price change in a header (or in the JSON itself, if you post multiple
products). If the price changed, the server could respond with a 412 -
Precondition failed. If you want to post a collection of items, maybe you
could use If-Match. If you want to enforce this, you could return a 428 if the
client didn't include some sort of preconditions.

[http://tools.ietf.org/html/rfc6585#section-3](http://tools.ietf.org/html/rfc6585#section-3)

REST doesn't mean "Never user Headers".

~~~
Mister_Snuggles
There is no consistency problem.

Every product has a price, every product listed on an order has a price, these
aren't necessarily the same thing. What if the order includes something that
the manager threw in for free to sweeten the deal? The price of that product
on that order is zero, but the product's list price at any given point in time
was not zero.

~~~
batbomb
I didn't say there is a consistency problem, I quoted FTA.

My suggestion actually has nothing to do with the price of the object, it only
has to do with the server state of the object (product) and whether or not
that state was updated (price, quantity available, etc...), which is what the
article was worrying about (the lost update problem).

i.e. if the underlying objects in a transaction changed between the time a
client retrieved information about the object and the time where a user was
interested in creating an order with the object, in a way which might
invalidate the transaction, I'm highlighting a potential solution to notifying
the client.

    
    
         What if the order includes something that the manager 
         threw in for free to sweeten the deal? The price of
         that product on that order is zero, but the product's
         list price at any given point in time was not zero.
    

Well, in that case, I hope there is a system the "manager" can create a
discount object to and attach it to the order.

    
    
         PUT /orders/12345?discount=FREE_IPAD_YO
         PUT /orders/12345;discounts [{"discount_id":"FREE_IPAD_YO"}]
         whatever flavor you want, etc...
    

Note: I don't work in the ecommerce domain, but I do develop systems which are
often transactional in nature.

------
jamesfisher
> Values are identified by random UUIDs

Alternatively and preferably, values are identified by a cryptographic hash.

~~~
rubyfan
Why is that preferable? I'm not even convinced a uuid is appropriate to solve
the problem.

~~~
weavejester
The proposed protocol allows for PUTs, which means the server needs to
atomically check whether or not that UUID is already in the database. Using a
cryptographic hash as an ID removes the need for atomicity in the case of
PUTs.

------
tyrion
I am not sure you are talking about REST. I don't see any Hypermedia controls
in the examples..

------
jprince
My only concern is if the app wants the value immediately. I don't want to
have to make a separate GET after receiving a VALUE url to get the info. I
understand why this is useful if I'm passing it along, but what if I'm not?

~~~
1_player
You don't have to worry as, I would suppose, redirects are resolved
automatically by the browser or any sane HTTP client library.

~~~
michaelmior
This still results in increased latency at worst as you may now have two round
trips for every GET.

~~~
simonw
I think you could solve this using SPDY, which lets to send an expected
follow-on request in the same stream of bytes before it has been requested -
originally designed for things like CSS but it should apply equally well here
(especially given the UUID URL caching semantics)

~~~
notdonspaulding
Whether or not that's more efficient boils down to how much the server can
predict the client's behavior though, right?

I'm just thinking that if the server was configured to respond with the
/value/ reference and then immediately follow that up with the resource, your
client doesn't really have much say in how noisy the conversation is over the
wire.

------
stevejones
Yet another critique of REST by someone who doesn't understand REST.

(product_id should be a hypertext reference to the product resource, not an id
- you should be able to work out the rest (no pun intended))

~~~
notdonspaulding
How does a "hypertext reference to the product resource" differ from
/product/12345/ or /values/some-long-uuid-here/ ?

Giving you the benefit of the doubt that you'll come up with a good list of
differences, it really seems like you're just agreeing with the author.

------
eric_bullington
Would this be kind of like a functional lens? Like a RESTful lens?

------
vdm
Twitter thread:
[https://twitter.com/dozba/status/501782989257187329](https://twitter.com/dozba/status/501782989257187329)

------
martin_
Isn't the solution to your problem widely adopted since the early 90s? Store a
checkout, push and pop products to it and then total up the real time values
when the transaction is completed. Passing the value to be charged through in
the POST is incredibly insecure.

