1

TL;DR

In my current API, I've got two endpoints to handle the context:

GET /context/get
POST /context/set '{"id": "123"}'

What's the recommended way of having this global, id-less state accessible from RESTful API?

Please assume that the context concept can't be changed.

Background

Let's say I've got a user that is logged. He's by default assigned to a context that he can change.

After the context change, all the subsequent API calls will return different data, according to the context.

Example:

// Backend
Context = "Poland"

then

$ curl -X GET http://api.myapp.com/cities

will respond:

{
  "cities": [{
    "id": "1",
    "name": Warszawa"
  }, {
    "id": "2",
    "name": Wrocław"
  }]
}

However, if you change the context:

// Backend
Context = "USA"

then, the same URL:

$ curl -X GET http://api.myapp.com/cities

should return the different set of data:

{
  "cities": [{
    "id": "3",
    "name": New York City"
  }, {
    "id": "4",
    "name": Boston"
  }]
}

Question

As the context is just a global state on the backend side, it doesn't have an id. It doesn't belong to any collection either. Still, I want it to be accessible in the API. There are three possible solutions I see:

Solution #1 - existing

Set a context

$ curl -X POST http://api.myapp.com/context/set '{"id": "123"}'

Get a context

$ curl -X GET http://api.myapp.com/context/get

This one doesn't really feel like a RESTful API and still, on the frontend side, I have to mock the id (using ember-data). And the resource name is singular instead of plural.

Solution #2 - mocking the id

Set a context

$ curl -X POST http://api.myapp.com/context/1 '{"contextId": "123"}'

Get a context

$ curl -X GET http://api.myapp.com/context/1

Here I mock the id to always equal to one but I feel that it's super hacky and certainly not self-explanatory... Moreover, I've got a name conflict: id vs contextId. And the resource name is singular instead of plural.

Solution #3 - actions

Set a context

$ curl -X POST http://api.myapp.com/context/actions/set '{"id": "123"}'

Get a context

$ curl -X GET http://api.myapp.com/context/actions/get

This is very similar to the first one but using actions that could be a part of my whole API design (taken from e.g. gocardless. Still, I'll have a problem how to model it on the frontend side nicely. And the resource name is singular instead of plural again.

Is there any #4 option? How should I address this problem?

Thanks!

andrusieczko
  • 2,824
  • 12
  • 23

2 Answers2

2

Your three solutions are RPC, not REST. Not only they are not stateless, but setting a resource to some other resource by setting an id is very RCP'ish.

A RESTful solution, if you really want to go that way, is to set the context in a header. The client should send a header like X-ContextId or something like that, and you determine the request context you need from that.

However, don't worry too much about being RESTful if that's not what your application requires. I recommend reading the answer here: SOAP vs REST (differences)

Community
  • 1
  • 1
Pedro Werneck
  • 40,902
  • 7
  • 64
  • 85
  • 1
    Hey, that was a really helpful answer. The link you provided hits the point. I was surprised with http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven also. That's great reading. Your idea of headers is worth considering, thanks! (the X-Headers were deprecated: https://tools.ietf.org/html/rfc6648, still I could use my own one though). Learnt a lot! Thanks! – andrusieczko Mar 18 '15 at 02:53
  • Hey, what about the situation, when the `context_id` is being passed through cookie but it's encoded (can't have sth like context_id=123 explicitly in the cookie)? Then, I still have to ask the server for the resource: `GET /context/get` – andrusieczko Mar 31 '15 at 04:21
  • If you're asking if that is RESTful or not, the short answer is that cookies are never RESTful. – Pedro Werneck Mar 31 '15 at 12:59
1

What's the recommended way of having this global, id-less state accessible from RESTful API?

A RESTful API is by definition stateless, no client context should be stored on the server between requests.

If you want your API to be RESTful, you'll have to pass this id with each request.

Veve
  • 6,643
  • 5
  • 39
  • 58
  • Yes, you are correct. As I noted at first, I can't change the concept of *context* state though. I hate the idea of my API not being RESTful either. So now, in not-super-ideal-real world - what's the best approach? How can I have 99% percent of my API being RESTful, and these 1% excections to be handled in a nicest possible way? – andrusieczko Mar 18 '15 at 02:05
  • Look @PedroWerneck answer(s), his suggestion about the custom header should allow it. – Veve Mar 18 '15 at 02:36