What’s the best RESTful method to return total number of items in an object?

Viewed 181823

I'm developing a REST API service for a large social networking website I'm involved in. So far, it's working great. I can issue GET, POST, PUT and DELETE requests to object URLs and affect my data. However, this data is paged (limited to 30 results at a time).

What would be the best RESTful way to get the total number of say, members, via my API?

Currently, I issue requests to a URL structure like the following:

  • /api/members - Returns a list of members (30 at a time as mentioned above)
  • /api/members/1 - Affects a single member, depending on request method used

My question is: how would I then use a similar URL structure to get the total number of members in my application? Obviously requesting just the id field (similar to Facebook's Graph API) and counting the results would be ineffective given only a slice of 30 results would only be returned.

14 Answers

As of "X-"-Prefix was deprecated. (see: https://www.rfc-editor.org/rfc/rfc6648)

We found the "Accept-Ranges" as being the best bet to map the pagination ranging: https://www.rfc-editor.org/rfc/rfc7233#section-2.3 As the "Range Units" may either be "bytes" or "token". Both do not represent a custom data type. (see: https://www.rfc-editor.org/rfc/rfc7233#section-4.2) Still, it is stated that

HTTP/1.1 implementations MAY ignore ranges specified using other units.

Which indicates: using custom Range Units is not against the protocol, but it MAY be ignored.

This way, we would have to set the Accept-Ranges to "members" or whatever ranged unit type, we'd expect. And in addition, also set the Content-Range to the current range. (see: https://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.12)

Either way, I would stick to the recommendation of RFC7233 (https://www.rfc-editor.org/rfc/rfc7233#page-8) to send a 206 instead of 200:

If all of the preconditions are true, the server supports the Range
header field for the target resource, and the specified range(s) are
valid and satisfiable (as defined in Section 2.1), the server SHOULD
send a 206 (Partial Content) response with a payload containing one
or more partial representations that correspond to the satisfiable
ranges requested, as defined in Section 4.

So, as a result, we would have the following HTTP header fields:

For Partial Content:

206 Partial Content
Accept-Ranges: members
Content-Range: members 0-20/100

For full Content:

200 OK
Accept-Ranges: members
Content-Range: members 0-20/20

You could consider counts as a resource. The URL would then be:

/api/counts/member

Interesting discussion regarding Designing REST API for returning count of multiple objects: https://groups.google.com/g/api-craft/c/qbI2QRrpFew/m/h30DYnrqEwAJ?pli=1

As an API consumer, I would expect each count value to be represented either as a subresource to the countable resource (i.e. GET /tasks/count for a count of tasks), or as a field in a bigger aggregation of metadata related to the concerned resource (i.e. GET /tasks/metadata). By scoping related endpoints under the same parent resource (i.e. /tasks), the API becomes intuitive, and the purpose of an endpoint can (usually) be inferred from its path and HTTP method.

Additional thoughts:

  1. If each individual count is only useful in combination with other counts (for a statistics dashboard, for example), you could possibly expose a single endpoint which aggregates and returns all counts at once.
  2. If you have an existing endpoint for listing all resources (i.e. GET /tasks for listing all tasks), the count could be included in the response as metadata, either as HTTP headers or in the response body. Doing this will incur unnecessary load on the API, which might be negligible depending on your use case.

Seeing that "X-" prefix was deprecated. Here's what I came up with:

  1. Added another item count:23 to the response
  2. Removed the item from response before using data in the app.
Related