Designing
APIs often leads to a compromise between producers and/or consumers. Consumers
of APIs would like the interface to be as close to their requirements as
possible; they want to avoid possible composition or contract navigation. API
producers would like their interface to be as simple as possible; they want to
support maximum reuse and consumption.

I’ve
touched on this in a previous article, Should
APIs be Pre-made or Deli style?
, where I offered different options
for consumer flexibility or producer simplicity.

Pre-made. Defining API interfaces
based on specific consumer needs – simple for each consumer, but not
necessarily reusable.

Deli-style. Defining an API
interface that allows consumers to select the attributes they need via
arguments in the request – maximum flexibility for the consumer, but at a cost
for the producer.

Providing the entire model as one
interface
. Allowing the consumer to pick the elements they want from the
response and discard the rest – simple for the producer, requires contract
navigation for the consumer.

For this
discussion, let’s look at how we can make the third option a little more
flexible for the consumer while keeping it simple for the producer.

Assume this
is the entire model of a car:

It’s a fairly
simple model, but I’ll use it to explain the approach.

A producer
could expose the entire model via GET: /cars/1234abcd. This would force the
consumers to download the entire model and find the values they need. It’s the
simplest for the producer, but will probably get challenged by consumers if the
model is large.

An
alternative is to expose each sub-object as a separate URI – giving consumers
the basic information about the car and links to allow them to discover more about
the model through hyperlinks (HATEOUS).

This reduces
the payload of the response, and allows consumers to retrieve the additional
data they might need independently. From a producer’s perspective; each object
can be managed in isolation, it’s still simple and supports maximum reuse. For
the producer it offers flexibility and reduced payload.

However,
even this simple approach leads to another consumer argument: “What if I need
more than one object? I will have to make repeated calls to compose all the
data I need!
”. By example, assuming a consumer was interested in a car’s engine
and body, this would result in the consumer having to make three API calls:

GET: /cars/1234abcd
GET: /cars/1234abcd/engine
GET: /cars/1234abcd/interior

Is there another
alternative here?

What about
using the HTTP URL Fragment? By definition (RFC 3986): “The
fragment identifier component of a URI allows indirect identification of a
secondary resource …”. This is donated in a URL as the “#” (hash) symbol and
allows users to navigate to a specific portion of an HTML document.

We could
use the HTTP URL fragment to identify secondary objects within a model, and allow
the API consumer to define which objects in the model they are interested in. Since
we already have these objects exposed via end-points, we can offer a
short-circuit URI using the fragment, as follows:

GET:
/cars/1234abcd#engine,interior

The resource
in question is still the car, but the consumer is asking for additional sub-resources
of the car known by “engine” and “interior”.

Obviously,
only requesting one object via a fragment is redundant, but I believe this does
offer a lot more flexibility for the consumer without introducing too much complexity
for the producer.

Let me know
your thoughts.

Photo by Lukas from Pexels