This is the next in a series of posts on RESTful web API design based on my experience of designing and building a set of public RESTful web services for a popular online platform. This post highlights the importance of upfront design of a separate model for REST resources, and contains suggestions on how to implement such a resource model in an API service’s application architecture.
1. The Resource Model
When designing a set of RESTful web services for an application it’s important to establish and maintain the concept of a resource model. The resource model comprises the types of resources publicly exposed by your APIs, the operations supported by each type of resource, and the relationships between the resources.
The resource model of a public API should be separate (decoupled) from the application’s domain object model for several reasons.
1) Allow for HTTP / object impedance mismatch – The resource model is the hypermedia document-oriented view of the domain. This is what works over HTTP, which is often not the same as what works for your object-oriented domain model.
The constraints of the uniform interface (HTTP methods) imposed by REST may lead to there being more types of resources than domain classes – resources can be finer grained than domain objects / entities.
Resource granularity can also be dictated by factors such as network efficiency, the (data) size of representations, and clients’ data usage patterns, rather than what exists in the object or data model. Creating different resources for data which have different lifetimes or update intervals can also improve performance, as they can have different caching policies.
2) Conceal complexity – The resource model should be designed with API client developers in mind. One thing you’ll want to do is conceal any unnecessary complexity, including historic baggage, in the application’s domain model. This may mean aggregating your domain model to expose fewer, simpler concepts in the resource model.
3) Maintain a stable public interface whilst allowing internal evolution – You’ll want to be able to evolve your domain model as your application matures or your requirements change. Counter to this, a public API needs to change more slowly to provide API clients with stability. Versioning your APIs / resources can help with this but it’s a last resort. You don’t want the need for stability in your APIs to slow down your own internal developments. Decoupling the external facing resource model can avoid this constraint and prevents your public API being too fragile.
A public API’s resource model should be viewed as a representative public facing model of your application domain, that allows for the constraints of REST and HTTP. It is the API’s responsibility to mediate between these two models, decoupling API clients from the application domain model in the process. This is illustrated in the following logical diagram:
2. Designing the Resource Model
When designing public web APIs I’ve found the best results are achieved by following a top-down, upfront approach.
The previously stated aim of creating a resource model that is decoupled from the application domain model can be achieved by designing your RESTful resources and their representations in a top-down manner. This approach, also referred to as contract-first API design, is the practice of designing an API starting from its public interface as opposed to reverse-engineering it from the application’s existing object model. It provides the opportunity to create a set of resources and representations which work best for both the API service and its API clients, in terms of complexity, consistency and performance. It also allows you to model resource meta-data such as hyperlinks representing resource relationships, which doesn’t exist in the domain model.
RAD tools which auto-generate API endpoints from your existing domain model / entities are now widely available for most development platforms, e.g. for Java+Spring – Spring Data REST. These tools adopt the opposite, bottom-up approach approach in the interest of building APIs more quickly. While this may be useful for APIs which are only consumed internally (and which you are at liberty to deprecate more quickly), I wouldn’t recommend using such tools to build public APIs as in all likelihood they’ll be too fragile.
Today’s popular agile methodologies favour evolutionary design over upfront (planned) design. Whilst this can be advantageous when building many kinds of software it isn’t suited to building any type of public API. Public web APIs need to present a consistent and stable interface to a service to simplify a customer’s task of building the API client and to minimise the ongoing costs involved in maintaining the integration. This isn’t compatible with evolutionary design. Undertake the design of as much of your resource model as possible before releasing any of the APIs. This will improve the consistency of your APIs and go some way to increasing their longevity, minimising the need to bump your API / resource version or deprecate APIs.
3. Implementing the Resource Model
From a logical perspective, the objects / entities in your application domain model need to be converted to / from the resources exchanged over your public APIs.
Based on practical experience of building public APIs (mostly on the Java platform), I advocate creating a separate set of objects (POJOs) to represent REST resources. This isn’t’ essential as you can convert your domain objects to resource representations on-the-fly as part of serialisation. It does also create an extra layer of objects to maintain. However this layer is simple and thin, and there are some benefits to be had from its existence –
1) It clearly distinguishes and serves to remind API developers of the existence of a separate resource model and its composition. It makes it easier to visualise each of your resources, including their relationships, in your IDE.
2) When using a data-binding API (such as JAXB) to serialise / deserialise your objects to / from their representations, if you use an annotation-driven approach to declaring the mapping rules, it avoids cluttering your domain objects with these presentation-layer concerns.
Having decided to create a separate separate object model for the REST resources, you need a set of classes for mapping the resource objects to / from your domain object(s). The role of this type of class is similar to an Assembler in the Data Transfer Object (DTO) pattern which transfers data between the DTO and one or more domain objects.
I’ve experimented with using object-data mapping frameworks (such as Dozer) to remove the need to code the mapping logic for each resource object. Such frameworks provide a powerful, generic implementation of a single mapper class which, using conventions, support for data-type conversion, and declarative mapping rules, are able to map two objects of any type. However, in the end we chose not to use them, and to code each of the mapper classes ourselves for a few reasons. The resource classes also contain links representing resource relationships which need to be built. Also, some custom mapping instructions in the form of XML config was needed to handle cases where fields were being flattened in one of the two object models. Given these two points, it was just easier to code the mappings.
The diagram below shows an example of the aforementioned classes in the implementation of our resource model, and the separate domain model.
Establish and maintain the concept of a resource model in your public API service, separate from your internal domain model, and have the API mediate between the two models.
Design your public resource model upfront, in a top-down approach, rather than reverse engineering it from your internal domain model.
Create a set of objects (e.g. POJOs) in the presentation layer of your API service to represent your public REST resources, and use a set of mapper / assembler class to map data to / from resource and domain objects.