How to handle endpoints that don’t return a resource object(s) as its primary data


#1

Hi everyone,
I am writing an api that exposes an Elastic Search api and was hoping to format the response using the JSON API Spec.

Currently the api looks like this:

Historical percentiles

  • Example:
    /historical_percentiles?field=someField&start_time=1478810146&end_time=1478810158&bin_interval=second

Returns the percentiles for a field over a range of time.

  • Parameters:
    • start_time (required) Unix epoch time
    • end_time (required) Unix epoch time
    • field (required)
    • bin_interval (required) Elastic Search compatible interval string
    • filters (optional)
{
  "meta": {
    "time_to": "2016-11-05T01:34:31.597836+00:00",
    "time_from": "2016-10-08T01:37:51.597836+00:00",
    "bins": [
      {
        "5.0": 361.5706796497282,
        "25.0": 729.7459890881007,
        "1.0": 327.0,
        "95.0": 5520.63477722484,
        "75.0": 2844.4385814706948,
        "date": "2016-10-08T00:00:00.000Z",
        "99.0": 8380.986835876729,
        "50.0": 1617.47585721036
      },
      {
        "5.0": 365.73289647286674,
        "25.0": 779.2334616130121,
        "1.0": 328.0,
        "95.0": 5440.772302540405,
        "75.0": 2795.7787375257903,
        "date": "2016-10-09T00:00:00.000Z",
        "99.0": 8345.435844243311,
        "50.0": 1819.0584232227932
      }
    ]
  }
}

Ideally, I would like to wrap the payload in the data property, but JSON API spec requires that data returns a resource or resources, which must have an id and type.
The only performant way (that I can think of) to have an id for this payload would be to base64 encode the endpoint with query params.

/historical_percentiles/base64encodedEndpointWithQueryParams

{
  "data": {
    id: 'base64encodedEndpointWithQueryParams',
    type: 'historical_percentiles',
    "time_to": "2016-11-05T01:34:31.597836+00:00",
    "time_from": "2016-10-08T01:37:51.597836+00:00",
    "bins": [
      {
        "5.0": 361.5706796497282,
        "25.0": 729.7459890881007,
        "1.0": 327.0,
        "95.0": 5520.63477722484,
        "75.0": 2844.4385814706948,
        "date": "2016-10-08T00:00:00.000Z",
        "99.0": 8380.986835876729,
        "50.0": 1617.47585721036
      },
      {
        "5.0": 365.73289647286674,
        "25.0": 779.2334616130121,
        "1.0": 328.0,
        "95.0": 5440.772302540405,
        "75.0": 2795.7787375257903,
        "date": "2016-10-09T00:00:00.000Z",
        "99.0": 8345.435844243311,
        "50.0": 1819.0584232227932
      }
    ]
  }
}

I don’t like this method for a number of reasons:

  1. the id could take up more space than the actual data being returned eg. (user enters many filters and one bin is returned)
  2. the documents are stored for a finite period of time; the user would not be able to retrieve the same resource again after some period of time by using the id and type.
  3. added complexity and redunancy of having to handle query params and base64 encoded id
  4. frequency of use, I doubt the consumers of this api would ever use the id to retrieve data

Because of these reasons, I’ve put it in meta for now. My reasoning is the api is returning data about stored data, which technically is meta data of the resource.

Is there a better way to handle this that is JSON API compliant?
Should I handle this use case separately and add it to our version of the JSON API spec?

Thanks for reading,
Andrew Toy


#2

Given that the returned data is not a resource, I feel like you should ignore the desire to place the data in the data member.
Unless I’m mistaken, the data seems to be inherently read-only. Thinking of an approach to assign an ID to the data set seems pointless as you’re unlikely to want to refer to the same data set (through the ID) again.