6

I'm reading Roy Fielding's dissertation Architectural Styles and the Design of Network-based Software Architectures, which introduces the REST architectural style.

Roy explains that cookies are a violation of REST as they introduce stateful behaviour - cached responses may no longer apply (for example, hitting the back button), and server-side statelessness is a constraint of REST.

There is no reason why the client should not maintain state however, this is perfectly acceptable.

So if I have a RESTful API - for an online store for example - and I want to persist user state client side for a long time - between multiple sessions, are there any alternatives to using cookies to persist local state in modern browsers?

If it matters, I assume I'm running a javascript app in the browser.

Are there any ways I can create client-side-only cookies?

This question is related a similar question about cookies for authentication in REST...

UPDATE:

...but in my case I am not concerned with authentication strategies - just in how to persist state between sessions without sending state to the server.

To give the discussion better context, when talking about cookie based authentication, Roy says:

cookie-based applications on the Web will never be reliable. The same functionality should have been accomplished via anonymous authentication and true client-side state.

perfectionist
  • 627
  • 7
  • 15
  • 2
    There's HTML5 local storage, which allows you to keep data without it contaminating the HTTP requests you make. – pjc50 Feb 19 '15 at 13:49
  • Question: does the no server-side statelessness constraint include databases, etc.? Or is it only limited to sessions and similar mechanisms? – Jonathan van de Veen Feb 19 '15 at 14:02
  • 1
    @JonathanvandeVeen yes, you aren't allowed to have a per-user "session" or "basket" type storage on the server in any kind of persistence. I believe (though there may be other reasons) that this is because per-user state cannot be allowed to pollute the content and context of requests. For example, if I have a `myshop.com/basket/` url, that serves user-specific content, this is a clear violation of the "resources" and "cacheable" principles of REST. Worse would be a catch-all `myshop.com/checkout/` POST action. All requests should be serveable without any knowledge of outside context. – perfectionist Feb 19 '15 at 14:14
  • So how do you actually handle the checkout in your example? You should have some kind of database to store this in right? – Jonathan van de Veen Feb 19 '15 at 14:40
  • @JonathanvandeVeen yes, of course you store it. But the idea is that you update the state of the resource, not pass it around. So the basket is a resource in itself that is updated via POST requests. If the basket is held in a cookie, Logging in on a different client will not show my basket. Don't mix up per-user (ie connections) and per-user (ie per-user-secured resource). – gbjbaanb Feb 19 '15 at 15:00
  • @pjc50 - maybe this should be an answer? – perfectionist Feb 19 '15 at 15:42
  • @JonathanvandeVeen my basket should be client side only. When I want to check out, (in an ideal REST solution) I would POST the entire basket contents to a (secure) "place order" URL, which would create my order for me. This way the process of browsing for items is stateless, and checking out is atomic. - and yes, in an **ideal** solution, if payment is involved then that should probably be part of the same "place order" POST. – perfectionist Feb 19 '15 at 15:46

4 Answers4

3

There's HTML5 local storage, which allows you to keep data without it contaminating the HTTP requests you make. It's intended for pretty much exactly this use case: complex Javascript applications that want to store persistent information locally.

http://www.w3.org/TR/webstorage/

Note that REST doesn't mean banning all state from the server, sometimes you genuinely want to update things; especially in the "airline ticket" example you might want to explicitly create a "reservation" object before payment with a POST that returns a URL for the reservation. The client then hangs onto the URL, but the server-side object exists to prevent booking the same seat twice.

pjc50
  • 10,595
  • 1
  • 26
  • 29
  • Absolutely agree on not banning all state, when there is a valid business object - such as a reservation - which can be represented as a resource with a meaning. – perfectionist Feb 19 '15 at 16:38
0

The point that Roy Fielding makes about cookies relates to sending these cookies to the server and maintaining state on the server based on those cookies. Using a cookie purely client-side to store state for any period of time does not violate REST and actually doesn't concern the server-side at all.

EDIT: You could store a cookie on a path that is not used by your server. That way you can access it from your javascript, but it will never get sent.

Maarten Winkels
  • 336
  • 1
  • 3
  • Storing state in cookies that aren't read by the server could be a workable solution. Is storing a cookie on a "not used" URL good practice? (Depending on the scope of the answer I may be better off opening a new question for that) – perfectionist Feb 19 '15 at 15:42
0

You don't have to use cookies, but if you have secured resources (eg my shopping basket as opposed to your basket) then you do need some way to detect which request corresponds to which of us. That id is usually held in a cookie as the detection is performed on the server via expensive auth mechanisms you want to store temporarily and repeat every request.

logically there's nothing stopping you from performing the authentication on every request. (except in the real world you won't do this unless you have, say, client certificates proving your identity to the server)

I imagine you could use some unique identifier that is known to the client, and use that as a mapping between client and secured user id after login instead, but they're hard to come by and maintain security.

gbjbaanb
  • 48,354
  • 6
  • 102
  • 172
  • I've updated the question to clarify - I'm not asking about authentication, and server side state is out of bounds. I know that if there is no persistence server side, then I can't share my basket between multiple devices, for example, but I just wanted to know about client-side state persistence techniques. – perfectionist Feb 19 '15 at 15:39
0

You can use cookies to maintain client state, because they are a client side storage mechanism. You can use other client side storage mechanisms, for example websql or localstorage.

The only problem with the cookies, that session cookies are violating the statelessness constraint. So unless you use session cookies you are okay. You should ask yourself what would happen when the server reboots. In the case of session cookies, your session will be lost. In the case of normal cookies, nothing relevant happens, your requests will be responded the same way as before.

I think when the server writes the cookies that is a grey zone thing, especially if we are talking about HTTP-only cookies (which are not accessible in browser javascript). In this case the service directly changes the client state. We could argue that set cookie headers are part of the representation, but that's a half truth I think. If your REST API has a different domain than your client, then set cookies only on the client domain and access their content for example with client side javascript if we are talking about browsers.

I don't know whether caching and cookies conflict with each other. I don't remember such an issue.

You should use the Authorization header instead of cookie, but I think it is not a tragedy if you set the username and password in a HTTP-only header. Or you set a persistent cookie with some hash (if it is registered on the server as a resource for a long while). I think it is still safer than storing this data for example in the localstorage.

inf3rno
  • 1,209
  • 10
  • 26