Onions Have Layers, Ogres Have Layers, APIs Should Have Layers, Too!
by Amir Shevat
When I was at Slack and later at Twitch, we used more than 50 different software-as-a-Services (SaaS) cloud offerings to make our business go. From bug tracking to task management, from sales to HR, most of the software we used was SaaS. Most of these services were great and added a lot of value, and some even had great APIs that enabled us to create useful integrations. When an issue was resolved in Jira a notification would be sent by email or Slack. Life was sweet! Well, not so much.
Life in many companies looks like this today:
In this post, I will talk about why API integrations still suck, and how to un-suck them a little bit, using a great technique called API layering.
API Integrations Still Suck
Unfortunately, while most modern systems have APIs, there are still several hurdles that make using them a struggle, especially as you scale.
- Lack of API standardization. Different systems expose different APIs that come in a range of architectural styles (e.g. REST, GraphQL, etc.), use different data structures (e.g. user key can be an email in one system and a phone number in another), and many other aspects. This puts a strain on development teams who manage and maintain a multitude of disparate APIs.
- Multiple security models make management complex. Each system exposes different security models — OAuth, basic, m2m tokens, etc. This makes integrations riskier as these tokens are shared anew every time you integrate more systems, and all these keys in the wild create the need for major provisioning and ongoing maintenance.
- Insufficient capabilities. Most APIs are pull only, but many developers need to push and constantly pull to mimic the push, which requires expensive resources such as compute cycles and bandwidth and produces suboptimal responsiveness.
- Code is not reusable across APIs. A system API, for example, the Salesforce API, exposes functionality that is limited to its particular third-party system. If I need to add a “new client” functionality to two different integrations, I need to duplicate the API calls to Salesforce in each of my integrations. To add that code to a third system, I’ll rewrite it a third time, which is not practical at scale.
How API Layering Can Help
The common pains mentioned above cost organizations time and money. They are the result of different standards being used, as well as heavy fragmentation in APIs and services used by modern enterprises. The good news is that using a set of simple design patterns I call “API layering” can simplify and even resolve some of these pains.
Let’s explore these API design patterns, where we wrap one or more APIs with another API as a shim.
Expansion-Layer: Wrap one API with another to add functionality
In this use case, you have an API that exposes partial or limited functionality and need to add additional functionality through a wrapper API. For example:
When to use this pattern:
When the underlying API is insufficient to complete your use case — or if you need to add functionality to meet security and compliant requirements — use this pattern to enrich the data returned from the wrapped API.
Real-life example:
At Slack, our API was used both for Slack clients and our developer community. Developers told us that while the API worked well for many use cases, it assumes a rich client that can cache data. Things like mapping between user id and username were the assumed responsibility of the client. We had to expose third-party endpoints that wrapped the original API and added information needed for our third-party developers.
Reductive-Layer: Wrap One API with Another to Limit the Access to the Original API
In this use case, you do not want to expose the full API functionality, either internally or externally. This can stem from a need to protect sensitive information, mitigate the risk of impacting production, or other reasons. While a few systems provide granular API permission solutions, these are rarely enough for enterprise use cases.
When to use this pattern:
Use this pattern to protect and limit access to the original API. Even if the original API has a token that limits the permissions of certain actions, there might be use cases where you would not want to expose some endpoints regardless of the permission system they use.
Real-life example:
Google Cloud has a vast set of APIs available to Google engineers. Many of them are exposed today, but not all. When I was at Google the internal system and its API had an internal secret name that was not shared externally. Today you can read about it here.
Type-Converter-Layer: Wrap One API Type with Another
In this pattern, you wrap one API type (e.g. XML RPC, SOAP) with another as a shim. For example:
When to use this pattern:
Use this pattern when the underlying API or protocol is hard to use (most developers think that SOAP is a hygiene product) or not secure enough to use in a certain use case.
Real-life example:
This happened to us at Twitch. Our internal system API was GraphQL, but we did not want to expose this externally. Instead, we exposed a REST API externally and bridged it to GraphQL in the REST endpoints. Another example would be how Twilio exposes a simple API for telephony and SMS.
Aggregation-Layer: Combine One or More APIs into a Single Standard API
In this pattern, we want to consolidate and standardize several APIs to a simple and consolidated API. This can normalize fields in the API parameters or return value across these API calls. Here is an example:
When to use this pattern:
Use this pattern to consolidate disparate APIs into a consistent and standard API and make sure the inputs and outputs of the consolidated API endpoints match one another. Another big benefit is that the client only needs to have a single API key and not hold credentials for many different systems.
Real-life example:
At Twitch we created an API gateway that exposed this type of functionality. We had a microservices-heavy system without an easy way to standardize across these services. The API gateway helped developers create a single unified API for our clients.
Composition-Layer: Wrapping an API over other APIs to Expose Composite Business Logic
This is the most advanced pattern. In this one, you create your own business logic that encapsulates several API calls to different systems. Here is a variation of the example above using this pattern:
When to use this pattern:
Use this pattern to expose your company’s business logic, rather than the building blocks each system exposes. When done right, this is a very powerful pattern that simplifies and abstracts a lot of the complexity of using APIs and many service providers.
Real-life example:
A good example of this are the BFF APIs, where frontend clients need a simplified version in the internal systems. At Twitch, we had hundreds of microservices and it would have been a Herculean task for a frontend client to communicate with fractures of functionality, so a consolidated API made a lot of sense.
A Better Future
Good design patterns remove complexity. Today we are using more systems than ever to run our businesses — utilizing hundreds of API service providers in big organizations. Manually managing APIs using these patterns is doable, but can be too slow for modern organizations, which is why using an integration platform like Reshuffle can simplify and automate the process helping the business to become faster and more agile. Whatever method you choose to manage APIs, ensure that integrations drive efficiency, speed and scalability.