Driving API Client Resiliency: How to enforce Postel’s Law by violating Postel’s Law…

As a vendor of a SaaS used heavily by large enterprises, a key capability of our platform are APIs that allow integrations with our clients’ internal systems as well as our technology partners’ platforms.

The reality that follows any 2nd-party accessible APIs is that we often wield very little control over the quality of the client code that accesses our system — as such we must make our system resilient and assume the worst of our API consumers.

To allow as much forward compatibility as possible, we want any client code (whether internal or external) to follow Postel’s Law (well explained in PACT’s specification philosophy) to prevent integrations from relying on temporary side-effects in our APIs and ensure they are forward-compatible with minor changes in our APIs.

We’ve had examples in the past where client integrations broke due to a minor property ordering change or an additional property in the API response.

This poses real difficulty upgrading our APIs to newer versions despite their backwards-compatibility with the existing published contract.

In the past, while the contract was clearly outlined (in the form of documentation rather than code, at the time) and the 3rd-party developers who implemented the integrations were meant to follow it, commercial reality forced us to deploy compatibility workarounds which added complexity to our codebase.

Thus we want to ensure client code is built in a way which is both resilient and tolerant to backwards compatible API changes, but how do we influence an implementation that is outside of our control?

Counter-measures

We are planning to experiment with what are essentially counter-measures to unhealthy assumptions about the content of our API responses.

While we can’t control the quality of the client code, we can limit any assumptions 3rd parties can make as to the format of our API responses by introducing acceptable levels of variance into the response.

By acceptable, we mean any variations that are:

  • Easily added during the serialisation stage of the response without changing business logic, and
  • Still adhere to the API contract

You may still consider these measures dirty-tricks but they can potentially save us, our clients and our partners a significant amount of time & money. The irony of breaking Postel’s Law to enforce Postel’s Law is not lost on the team.

These are some of the counter-measures we will be trialling:

  • Mixed ordering of keys
    Intent: prevent client code from relying on ordering of properties.
    Method: Randomise ordering of keys within objects in the JSON response.
  • Empty values vs. lack of keys
    Intent: To prevent consumers from expecting properties which may be optional. 
    Method: When there is no value for a particular property, randomly choose whether to return it as a null value or no key at all — both acceptable according to the JSON standard. 
    Example: { a: ‘A’, b: null } or { a: ‘A’ }
  • Random fake keys with null value
    Intent: Prevent a consumer from choking when receiving a response with new properties. 
    Method: An occasional random key with a null value.

As a team we may decide to only turn these counter measures on in a our integration staging environments only — we haven’t decided yet — we’ll experiment with how these are received by our API consumers and report back.