Extend link objects with headers

I have an API that I’m building that uses the Prefer HTTP header that allows clients to request different representations of the same primary data for a resource. For example, because some of our resource objects have a lot of attributes, we wanted to provide a way to “prefer” a minimal set of fields:

GET /tasks?include=cloud
Prefer: fields=minimal

The previous request would return a “minimal” fieldset for each task resource object and any included cloud resource objects.

In order to let the client know of a minimal fieldset, I want to include a link as part of the tasks links member. However, because my request requires an HTTP header to be specified, there aren’t ways to provide this in the link object according to the specification.

I understand that one could use the meta to provide the headers, but I am looking for something that falls more in line with the specification. Would it make sense to propose that a link object can also include a header member that specified any additional headers to include with the link?

This is a job for a service profile description language like ALPS, not a hypermedia format like JSONAPI. I would also encourage you to make sure any non-standard representations sent using prefer:fields=minimal to be cache-control: no-cache as attempting to mix multiple representations with no URI difference will create huge headaches for proper cache management.

A hypermedia format is not enough to drive a hypermedia API, you need to have a profile(s) which describes the entire potential vocabulary, which would include the entire range of attributes, composite relationships, and affordances.

I wonder if it makes more sense to extend the fields query parameter to support when a resource object type isn’t specified, the server must return the specified preferred fieldset.

For example:

GET /tasks?include=cloud&fields=minimal

This way, the URL is cacheable and doesn’t interfere with the existing sparse fieldsets implementation.

Thoughts?

So, the ‘public private’ conversation here, has tangential relevance to this discussion because of the way I am looking at the problem.

I see this as a protocol or profile not message format design concern. When you consider the application of the conditional views of the same resource to the minimal view you describe, with the public / private discussion, what you see is both of them are the same desire triggered by different conditions.

Generally I really like the idea of utilizing the underlying protocol with the Prefer header, however I think in this case the application profile would be a better way to expose the functionality you want. First, it would be dynamic which wouldn’t cause binding issues to existing clients if you want to change the list of values for ‘fields=?’ down the road. Second this is the perfect scenario to use hypermedia controls defined in semantic profiles. For a client to try to build your multiple view requests would be onerous and if you generated the appropriate templated link for a consumer ahead of time, dynamic changes to your view would be trivial for client and consumer. If a true hypermedia API is not possible yet on your project, you could still use the profile to describe the view and give the client the means to build the appropriate sparse fieldset request dynamically without injecting protocol concerns into the message format.

Adding a shortcut like this to the protocol is a very slippery slope and JSONAPI has been very careful to stick to the appropriate level. If you add these syntactic shortcuts for protocol concerns to your format, you’ll end up with a bad format and poor adoption.

You could provide a means of making data shaping easier, or you could just provide the link to data view in the first place. You’re defining both either way yet in the case of header or ‘view name’ sparse fieldsets overload you require active involvement from the consumer to support changes, with hypermedia you do not. A rel name in the link of resource-minimal, resource-verbose or resource-dynamic etc. would suffice to separate the links semantically, and you could then add the request header Prefer: fields=? defined on the profile itself to expose the ability to show which view should be in the initial body, while setting the location header to the resolved canonical URL for the message for cache control purposes.

While in the end you could have a similar capability to the described header, I believe it becomes possible only through the use of the profile to define the range, not the protocol or format.

1 Like