Managing Multiple APIs Using an Adapter Pattern
Short guide on how to optimise HTTP API integrations in B2B business.
Join the DZone community and get the full member experience.
Join For FreeLet's imagine the problem: Your company creates a B2B product that provides a service for some other companies. This service helps client-company to resolve very specific problems of their customers. This customer can communicate with our company web app and do some operations. The results of these operations should be reported to the other company side.
Times go on, and now you have a few more clients that work by the same scheme. At first, you connect small companies one by one, but when you get to much bigger client companies, you discover that they use third-party API service providers and delegate all the integration problems to them. These API service providers act as a proxy for this toil of service reverse integration, which unifies the logic of cross-company communication on both sides. Due to the structure of presented business relationships, our company almost inevitably start to use a set of similar actions to communicate with dozens of different APIs for hundreds of clients in the future.
To make things easier, we should unify the communication logic between our services and external APIs.
The main idea is to create a single scalable transaction service and use it to transform some kind of unified DTOs into API-specific information and vice versa.
For HTTP, our adapters should be able to:
- Transform unified request DTO into API-specific request DTO
- Transform API-specific response DTO and HTTP status code into unified response DTO
To do so, firstly, we need to understand the building blocks of our communication.
HTTP request consists of:
- HTTP method;
- URL path;
- URL params;
- headers structure;
- request body (any format: JSON, XML, plain text).
HTTP response consists of:
- Response headers;
- Response body (may also contain an error code that must be combined with the HTTP status code and translated into a unified error code format).
All items listed above are illustrated on the next image:
It's important to understand which elements of communication may vary between API providers and which are client-specific. For example, in API URL: protocol, domain name, and port are Client specific parts, but the request URL path and URL params are API-specific.
After we know what elements should be unified in our adapters, we need to make sure we always use the right adapter for our request. The easiest way to do so is to use some unique ClientId to identify an API unique keyword from the database. After getting one, we can simply use static Map<API_KEY, ApiAdapter> to pass our data further.
It is highly recommended for unified request data to have full information about entities. This way, you will never experience a lack of information on the API adapter's side. For example, if a request into your transaction service contains the 'ClientId' field, consider getting full ClientEntity [clientId, apiKey, mainCurrency, URL_protocol, domain, ... ] from the database and pass it into your adapter (do it any way you are comfortable with).
After combining these 2 simple steps, we got the next code structure:
Now, whenever you need to do API reverse integration, you simply need to add new request and response adapters and do all necessary API-specific transformations in one place.
Opinions expressed by DZone contributors are their own.
Comments