Isolating API data model differences and smells from application code

Single-page web applications typically communicate with at least one API to retrieve data and perform actions. Differences and “smells” from these APIs’ data models can spread through the application codebase if we allow them to.

In this post, I show a few examples and describe a simple approach to confining them to a small corner of the codebase.

Differences, inconsistencies, and poor choices

Each API uses a specific capitalisation style for JSON property names, usually camelCase, snake_case, or PascalCase. Mixing one or both of the latter two with the camel cased identifier and property names in our JavaScript code causes inconsistency, which can make it difficult to remember which style should be used to access the properties of a particular object.

Property names can be abbreviated differently between APIs or even within the same API. Properties can also be named poorly, causing their meaning to be unclear and causing confusion — or they may simply be misspelt. Data types may be poorly chosen or applied inconsistently.

This made-up order object demonstrates some of these problems:

Fix the API

The best solution by far when faced with an API having these kinds of problems, is of course to fix the API. Doing so addresses the problem for all consumers, and also improves implementation code of the API. However, that may not always be possible — there may be existing consumers which the API needs to remain compatible with, or fixing it might not be a priority for the owner of the API, for example.

Practical solution — abstraction

So, we have to consume this API as it is, or we’re consuming multiple APIs which have different conventions. Adding a simple translation step immediately after parsing the received response allows us to normalise or tidy up the data at the first possible opportunity:

Now, we have a much nicer data object for use in the rest of our code:

Request data

The same cases as shown for response data above also apply to request data that our application builds up for sending to APIs. And the same pattern can be used to deal with it — perform translation immediately before sending the request.