I was out looking
for a sandwich for lunch the other day and found myself faced by two options; I
could either go to the convenience store and pick up a pre-made sandwich or go
to the deli and have one made for me.

The
pre-made option sounds simple, but choice it usually limited to the imagination
of the sandwich maker. Going to a deli to have a sandwich made offers freedom
of choice, but I’d have to deal with queues of people trying to make up their
minds about which ingredients they want (including me when I get there).

From the
stores perspective, the pre-made option is easy – display what’s on offer and
let the customer pick one; it’s quick and simple. However, reduced choice may
push customers towards the Deli. The Deli owner can offer his customers choice,
but at the cost of extra staff to make sandwiches based on each customers requirement.
The little effort required by customers and possible delays could push customers
to the convenience store for the “best fit” option.

Producing read
APIs could follow a similar approach.

Pre-made. As
an API producer, using the inside-out-approach, I could decide “what” my
consumers need and make a range of specific endpoints for them to consume. If
one endpoint does not cover all their requirements, they could compose the data
they need by consuming a number of my APIs; extracting the bits needed from
each. This will give me full control over my API implementation and allow me to
optimize them for better performance. Eventually however, my consumers will
complain and ask for more “specific” APIs to meet their needs. In my
experience, this is all too often the reality.

Deli style.
As an API producer, using the outside-in-approach, I could offer my consumers
the ability to select which elements in my API domain should be returned. This would
require me to provide proper documentation to explain my domain and I’d need to
implement the selection logic (and consequences) in my services. Like the Deli
needs to maintain the cost of a sandwich maker, I’d need to accept the cost of
maintaining this logic and implementing it for new elements in the future. The benefit,
of course, is that my API will offer complete customization, making it as
consumable as possible by more than one consumer – a desirable trait for APIs.

There is an
alternative – I could provide the full data object in the response. In other
words, provide all the data elements of the object being modelled and let the
customer extract the values needed, ignoring the rest (pun intended). This approach
creates less work for the producer – only one simple endpoint is required per
object. The effort is passed to the consumer, similar to the Deli style approach,
only the selection of elements is made on the response instead of providing
input into the request. Taking advantage of HATEAOS will reduce the payload
size and offer discoverability but could force the consumer to perform
composition in order to get all the data elements required.

So, as API
producers we have options. We can offer our consumers flexibility through
choosing data elements before or after request, or we can offer them what we
think they need – the choice is ours. Each approach has its merits and its consequences,
but they are nonetheless choices.

I’ve worked
on APIs that follow all three of these approaches. The Deli style approach offers
benefit to the consumer and reduces payload. The challenge comes in selecting data
elements for the request input in a hierarchical data structure. The approach
we took was simple; use dot.notation to identify the data elements just as you
would when reading the JSON response.

Image provided by Pexels.com