Rest – Retrieving JSON and image representation of a resource

hateoashttprestweb-api

I am developing a RESTful API designed primarily (but not exclusively) for consumption by a web application. For the purposes of this question, the API is a set of GET endpoints. The main endpoint is /people/ and understands a large amount of query parameters to refine the result set.

The web application's splash page initiates this request:

GET http://my.api/people/
Accept: application/json

And this responds with a body of:

{
  "results": [
    {
      "name": "john",
      "age": "21",
      "_links": {
        "self": "/people/john/"
      }
    },
    ... more people ...
  ],
  "_links": {
    "self": "/people/"
  }
}

The results array is used by the web application to populate a list view of the people, with their name and age, and also an image of the person.

The image can be retrieved with such a request:

GET http://my.api/people/john
Accept: image/png

From the perspective of the web application, this presents a number of difficulties.

  • The _links.self of an individual person can be used in a HTML <img> element as the src, however the request generated by this has a header of Accept: */*, which does not sit well with the API as the global conventional default type is application/json.

  • The image/png request could be manually sent via Javascript but this can result in a large number of concurrent XHR requests, possibly beyond the concurrency limit of some browsers

As I also have final say in the design of the API other possibilities are on the table:

  • The /people/ endpoint could be modified to return the image representation as Base64 (or some other text format) as part of the application/json response. This could also be excluded by default (and included manually with a include=images query parameter), so that requests are not forced to download image data for each response. This increases the response size massively, leading to slower response times for clients (especially mobile users) and potentially a cost increase due to increased outbound data from the hosting platform of the API.

  • The /people/john endpoint could be updated to default to an image/png response, however this goes against the grain of the rest of the API and is a change aimed exclusively at one client of the API.

  • The /people/ endpoint could return, in each result's _links dictionary, a direct link to the image e.g. my.api/images/people/john.png. This is looking like the best option with few drawbacks, however I do not know how well this incorporates into REST / HATEOAS.

What is the most appropriate solution, from a REST / HATEOAS architectural point of view, for retrieving the image representation of a resource as well as the JSON representation

Best Answer

What is the most appropriate solution, from a REST / HATEOAS architectural point of view, for retrieving the image representation of a resource as well as the JSON representation

I would expect there to be a separate link relation for your images.

  "_links": {
    "self": "/people/john/",
    "https://schema.org/image": "???"
  }

RFC 5988 describes both registered relation types and extension relation types. In a quick skim of the link relation registry, I didn't see a good match, so I think you are restricted to using an extension, which are required to be URIs. Image seems like a good choice from schema.org, but of course you could use spellings that are completely under your control if you prefer.

As far the target of that link relation, the client should just be treating that as an opaque value, so you can choose whatever spelling you think is going to make your life easier.

Choosing the same spelling for both the json and the image targets means that both representations will share the same key in the cache, and that in turn means that both representations will be invalidated together if an unsafe request is successful. (Of course, if you don't want that behavior, then sharing the same id is not going to be for your benefit).

As for the Accept headers, that depends on having clients that recognize your media type and its defined semantics. For example, in HTML we have the img element, and browsers that are smart enough to use different headers for fetching images than they use by default.