When calling into a third-party REST API, it’s OK to define high- and low-level operations, and leave out the middle.
At work, we wanted to manage mailing lists through the REST API of a company that specializes in email campaigns. Let’s see how we ended up close to the functional programming ideal of functions operating on plain data structures.
Data and the domain
A one-to-one mapping from functions to API operations was out of the question, as we only wanted to use a small subset of the API.
Instead of starting from the API, we started from our domain and defined our own interface.
We used Java and wanted type safety. Type safety required us to write code that mapped the JSON properties in the API response to the right types. Parsing the API response in the domain methods would mix concerns and duplicate code.
We decided to map the JSON objects to data classes that matched the structure of the JSON objects. Since the Java classes faithfully reproduced the JSON responses, we could rely on the same classes in all the domain methods. The data classes were easy to create, since we only had to map the basic JSON types like number and boolean to the corresponding Java types.
As we implemented our domain methods, we noticed a third concern: storing and retrieving the API key.
Shh, it’s a secret
Secrets are turning into an ever bigger concern for developers as developers rely on more on cloud provider APIs. Luckily, secret management is orthogonal to our domain, so we could move it into its own service. Our small-scale architecture exercise was complete.
No middle ground
When interacting with the email provider API, we left out an API class with methods that match the API calls. We’re better off with objects close to the raw data and methods close to our own domain, and a separate service to manage secrets.