Architecture

We start our modeling with an ApiClient class and an accompanying interface. The key pieces that work with the ApiClient class are the DTOs, Operations, and Exceptions.

ApiClient

This is the main class our consumers will be interacting with. It exposes:

A method used to set the environment at runtime In our case, this was useful due to our WinForms app being able to switch to the test environment on the fly.

A property that tells us what the currently-targeted API environment is.

All of the operations.

We’ll use the matching interface IApiClient to create a singleton instance of this class using a dependency injection framework so that the underlying HttpClient and associated handler are kept alive the way they need to be.

DTOs

These are POCOs which acts as the common contract between the consumer(s) and our API. They’re kept in their own separate project so that we can package and publish them separately. We’ll talk more in detail about this in the Packaging section.

Operations

Here, we start with a BaseOperation which holds all of the major logic having to do with calling out to the API, handling retries (using Polly), and validating the response - handling exceptions when necessary. The BaseOperation is abstract and takes the TRequest and TResponse generic parameters. This class makes it simple to implement any endpoint as its own Operation.

Each of these inherits the BaseOperation and represents an endpoint. In doing so, the Operation is required to implement the abstract Call(TRequest) method. In our example HealthCheckOperation, we demonstrate using an optional parameter if a request object is unecessary as in cases of RESTful GET requests. Some more examples are available in the Extending section below.

All of the operations are internal, not exposed to consumers. The IApiClient interface will be where we choose how to expose these operations to API consumers.

Exceptions

We have two exceptions which can be handled by the library user:

ApiSecurityException Thrown when there is an error when obtaining an OAuth token.

ApiCallException Thrown when an unsuccessful response is returned and otherwise unhandled.



When thrown, both of these exception types will contain the inner exception.

Extending

When implementing a new endpoint, create an operation class which inherits the BaseOperation<TRequest, TResponse> where TRequest is the request DTO type and TResponse is the response DTO type.

Example: