9

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.

Yogi
  • 609
  • 1
  • 8
  • 21
Arūnas Smaliukas
  • 3,231
  • 6
  • 27
  • 46
  • for your example with the currently-logged-in user, couldn't the id be the userid? – Nathan Hughes Apr 10 '18 at 13:05
  • Don't use json-api. – Quazer Apr 10 '18 at 13:06
  • @NathanHughes yes it can.. but I don't like it :)) Then I should send request to `http://example.com/stats/` also?.. – Arūnas Smaliukas Apr 10 '18 at 13:20
  • @Quazer don't use it for these endpoints or don't use it at all? – Arūnas Smaliukas Apr 10 '18 at 13:46
  • @ArūnasSmaliukas If external system with JSONAPI as apriori doesn't connect to your project - don't use JSONAPI. Use own JSON. Endpoints for C# - RestRequest, Python - Requests. – Quazer Apr 10 '18 at 16:10
  • Similar problem here. I need to serve the stats for a particular collection of resources. An example for that would be the stats from a store's orders, like how many orders are in pendent payment or pending shipping status. The first approch would be using the `meta` field for that. But would not be desirable to fetch/serialize any resource yet. An alternative would be create a resouce called `OrdersSummary`, containing the stats only. But here we face the same problem. We haven't an ID. This is just an abstract resource, contaning any identification. – Theo B Mar 08 '22 at 21:48

2 Answers2

6

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" } } }

n2ygk
  • 449
  • 1
  • 5
  • 11
3

I'm no JSON API expert- but it's worth noting that while JSON API is a concrete specification, it is not the same thing as JSON, nor as a REST API. If you don't like its semantics, I agree with commenters who argue, "Don't use it." If you are going to use JSON API, do so in a compliant way, where every response is a resource; every resource has an ID and a type; and additional information is supplied as attributes of the resource.

Toward your question, I'm thinking about something similar where my application returns computation results. Now on the one hand, these are not strictly "resources" and so I've been toying with the idea of returning the raw result as an array (which I believe would be valid JSON, with a caveat), e.g:

[ 47 ] 

On the other hand, there is the idea that the results are the results of a computation that the client specified RESTfully, in which case one of the following two cases is likely true:

  • The same request submitted later is likely to have the same result. This suggests that in fact the result really is a resource.
  • The same request submitted later is likely to have a different result. This suggests that the client may want to track how results change for various queries, and so at least the query parameters should be part of the response.

In both cases, the response really is a 'result' object, and even though it doesn't have an ID per se, it does have an identity. If nothing else fits, the ID could be the query that generated the response.

This seems RESTful to me. User @n2ygk suggests that this is not correct as regards the JSON API spec, that an ID should simply be a unique ID and not have another semantic interpretation.

I'd love to hear other perspectives.

  • 3
    I think there's a lot of unfortunate confusion between the jsonapi.org specification and the terms JSON and API, the former being a specific standard pattern for JSON APIs. A close reading of the jsonapi.org specification would still require you to represent this result as a resource with `type`, `id`, `attributes`, etc. The recommended `id` is a UUID (globally unique) so you could choose to return a new one each time or cache the result and return the same one.... I wouldn't use an ID that has other semantics though. – n2ygk Apr 26 '18 at 17:30
  • Thanks for these observations. I've updated my answer (hopefully) to reflect it. – Brandon Kuczenski May 09 '18 at 18:16