I’ve recently designed and built an open source API client for the REST API of a major enterprise video and webcast service, for use by its customers. It was a rewarding exercise that has helped me gain some valuable additional practical experience of emerging technology and tools for building and testing apps. This post outlines the value of the API client, its design, the technologies and tools I used, and how I rate them. I’ve open sourced the code to allow customers, and others, to view and reuse what I’ve built.
1) Benefits of the API Client
The API client provides a no. of benefits to developers that need to build a reporting integration to the service. It substantially reduces the effort involved in building one side of the integration by providing a simpler, higher (object) level programming interface for interacting with the web APIs, which abstracts the lower-level (HTTP) communications. It also encapsulates some of the technical complexities of the API, such as paging.
2) API Client Design
The API client code is organised into a number of Java package. The mains ones are shown in the diagram below, along with an indication of their purpose and the dependencies between them –
The reasons behind this package design include:
- The ‘client’ package encapsulates the public interfaces of the API client. External services which use the API client need only utilise these classes, to minimise coupling.
- Classes which are specific to a particular implementation of the API client, such as the out-of-the-box Spring implementation (see below), are contained in a separate package. Other implementations could be added in the future.
See the package-level javadoc (package-info.java) for more details.
A few of the most significant classes making up the API client’s interface are shown in the following class diagram:
The main points to note are:
- The ApiClient interface provides methods for accessing each of the web APIs exposed by the API service. By coding to this interface, users of the API client can avoid direct coupling to specific implementations which can then be swapped-out for different implementations, including mocks and stubs to support testing.
- The ApiClient returns de-serialised, object representations of the REST resources (and resource collections) exposed by the REST APIs.
- All exceptions thrown by the ApiClient extend the ApiClientException base class, itself a RuntimeException. The ApiErrorResponseException subclass reports errors returned by the API service, including RESTful error codes. These two points allow API client users to selectively handle errors, and to distinguish between API requests which fail due to client-side errors e.g. network connectivity errors, and those rejected by the API service.
3) API Client Implementations
A single implementation of the ApiClient is provided out of the box. This is built using a combination of Java (combined with Google Guava for additional language support), Spring MVC, and the Apache HttpComponents (4.x) HTTP client. The following class diagram provides an overview of this implementation, including customisations to Spring and the HTTP client –
Language – Java 7 was chosen over Java 8 to maximise the availability of the API client. (At the present time the install base for Java 7 is still much larger than 8. However, Java’s backwards compatibility commitment means you should still be able to run the API client on Java 8 JRE without problems). Google’s Guava library has been used to supplement Java 7 with additional language support (utilities, enhanced collections and functional programming).
Application framework – The Spring framework’s support for dependency injection and configuration make programming to interfaces and the creation of environment specific config very easy. And using the newer Java (@Configuration) approach for Spring bean definitions is very natural, making criticism of Spring’s need for a lot of XML based config a thing of the past. Add to this the availability of Spring’s other (e.g. MVC and test) modules, and it made a compelling case for using Spring to support building the Java API client.
REST client – The Spring MVC module’s excellent RestTemplate does the heavy lifting required to implement a synchronous REST client, including management of the underlying HTTP connection, binding of URL variables, marshalling and unmarshalling resource representations exchanged in HTTP requests and responses, and error handling (adapting HTTP status codes to exceptions). As shown in the class diagram above a custom Spring ResponseErrorHandler has been written to translate an HTTP error response to an exception. This avoids exposing the Spring implementation of the runtime exception in the public interface of the API client, and additionally supports unmarshalling the supplementary custom error response returned by the API service, making it available in the custom class of exception.
HTTP client – The Apache HttpComponents HTTP client supports a no. of essential features which Java’s built-in HTTP client (HttpURLConnection) continues to lack, including connection pooling, HTTP compression and correct handling of HTTP error status codes. As shown in the class diagram a minor extension to the Apache HTTP client has been written to improve the efficiency of the API client by performing preemptive (basic) authentication with the API service. (I’m hoping the new HTTP client promised for Java 9 will do away with the need for a library in the future).
4) Build Tools
I’ve provided both Maven (pom.xml) and Gradle (build.gradle) scripts for building the API client from source. Maven remains the most popular Java build tool since it pioneered convention-over-configuration in the Java build space, and its repository format for dependency resolution is now a ubiquitous, de facto standard. However, based on my experience to date, Gradle will be my Java build tool of choice going forward, rather than Maven. A build tool based on a programming language (Groovy) rather than plugins offers a get-of-jail-card that’s much easier to use in those cases where you need to customise your build. It has the essential support for Maven format repositories. And its excellent ANT integration provides access to the library of extensive ANT tasks without the pain of XML build scripts, as well as making the migration and reuse of old ANT build scripts possible.
5) Automated Testing
Unit tests are implemented in JUnit, with the Hamcrest (Matcher) library added to provide more readable assertions with better error diagnostics.
Integration tests have been written to verify the end-to-end operation of the Spring implementation of the API client.
The Spring MVC Test framework is used to exercise the API client end-to-end against a mock implementation of the API service, including loading the Spring application context, the production RestTemplate, and hence also the marshalling and unmarshalling of stubbed / canned API responses. These integrations test are very quick to run as they’re run in a single process, using a dynamic mock of the API service (MockRestServiceServer).
The integration tests built on Spring MVC Test provide very good but not full test coverage – the use of mocking means they don’t exercise the production HTTP client and its configuration. To address this an additional set of integrations tests have been written which dynamically stub (rather than mock) an out-of-process API server, using the WireMock library. In hindsight, I’d probably use WireMock alone to implement future integration tests, rather than writing two sets of integration tests.
A Continuous Integration job has been setup for the project using Travis CI, a free, hosted CI service for software projects hosted on GitHub. This has several benefits. It automatically regression tests the project on new commits. It also reassures users of the API client of the current status of the code based, which should mostly be –
6) Releases and Source Code
If you’re interested in the implementation of the API client, or have a need to build it from source, I’ve open sourced the code, under the Apache License 2.0. (This is one of the most permissive open source license, permitting incorporation and distribution of the code in closed-source code).
The code is version controlled using Git, and hosted on GitHub.
The GitHub project also includes binary distributions of releases of the API client which are available for download in both tar.gz and zip formats.
For more details, including a Getting Start guide, see the project’s readme on GitHub.
Thanks for reading.