Less Code, More Control, In Theory

One of the many interesting design decisions to look at when designing an app is how to encapsulate talking to the API. This isn’t a question that has a universal answer, and there are a lot of libraries that solve parts of the problem very well, but the final combination that takes you from hitting the API to displaying the result (including errors) isn’t a turn-key process.

In an effort to build on a recent services layer that I worked with, I went all in with operation, and tried to reduce duplicated code with liberal use of generics and protocols. At a high level the design consists of:

  • APIClient: Holds high level state for the API such as top level url session configuration, is loaded by APIService objects on init.

  • APIService: Manages which operation queue each step of API progress is handled on, and coordinates dependancies between “run network task”, “parse data” and “completion” tasks. Most of the logic here is implemented in the perform(action:completion) -> [Operation] function.

  • APIAction: Defines how to talk to each endpoint on the server, includes all of the configuration details for each request, and the functionality for parsing the response out of the returned data from the server.

So far with a whopping one endpoint and some unit tests, it’s been properly flexible and doesn’t require spreading configuration code over multiple files to hit a new endpoint, and clever use of subclassing means that most of the shared configuration only needs to be written once.

It’s too early to judge if this system is a total win, but it’s a promising start. It also feels very strange that I didn’t write most of the code for the final product. I code reviewed it, and I wrote the initial spec, but another developer on the team built the thing.