restapijson-apijsonapi-resources

JSON API for non-resource responses


Currently, I'm working on new product and making REST API for both - public and internal needs. I started with {json:api} specification and I was pretty happy with it until I faced some questions I cannot find answers to.

According to JSON API specification, every resource MUST contain id.

http://jsonapi.org/format/

Every resource object MUST contain an id member and a type member. The values of the id and type members MUST be strings.

And that's fine in many cases but not all.

Most of our endpoints are about "resources"

If I ask for a "things" collection (http://example.com/things)

{
  "data": [{
    "type": "things",
    "id": "1",
    "attributes": {
      "title": "first"
    },
    "links": {
      "self": "http://example.com/things/1"
    }
  }, {
    "type": "things",
    "id": "1",
    "attributes": {
      "title": "second"
    },
    "links": {
      "self": "http://example.com/things/2"
    }
  }]
}

If I ask for a single "things" resource (http://example.com/things/1)

{
  "data": {
    "type": "things",
    "id": "1",
    "attributes": {
      "title": "first"
    },
    "links": {
      "self": "http://example.com/things/1"
    }
  }
}

But what to do with endpoints which are not about resources and does not have ID?

For example, in our application, there is an endpoint http://example.com/stats which should return stats of current logged in user. Like

{
  "active_things": 23,
  "last_login": "2017"
}

There is no id for this "resource" (it's not actually a resource, is it?). Backend just collects some "stats" for logged in user and returns an object of stats. There many endpoints like this in this application, for example, we have Notification center page where the user can change email addresses for different notifications.

So frontend app (single-page-app) first has to get current values and it sends the request to GET http://example.com/notification-settings.

{
  "notifications_about_new_thing": "arunas@example.com",
  "notification_about_other_thing": "arunas@example.com"
}

And there are many more endpoints like this. The problem is - how to return these responses in JSONAPI format? There is no ID in these endpoints.

And the biggest question is - why nobody else is facing this issue (at least I cannot find any discussion about this)? :D All APIs I ever made has some endpoints which don't have "id".

I have two ideas, first is to fake id, like "id": "doesnt_matter", the second - do not use json-api for these endpoints. But I don't like both of them.


Solution

  • Think RESTfully and everything can (must) be a resource. There is no "logged in" user as there are no sessions in RESTful APIs as they are stateless. There's no session state maintained between REST API invocations, so you have to be explicit about who the user is.

    In this case, the resource is the user who has some stats attributes (in the simple case) or perhaps a relationship to a separate stats relationship (more complicated, not shown):

    GET /users/1234 { "data": { "type": "users", "id": "1234", "attributes": { "name": "etc.", "active_things": 23, "last_login": "2017" } } }