Design Patterns for Business Resource APIs

Enhance API composability and control over-fetching with sub-resources, filtering and field selection

TRGoodwill
API Central
6 min readMay 17, 2023

--

The setup and context of the following design patterns are described in this article:

The Business Resource

Business resources represent the nouns of a system, such as ‘applications’ and ‘applicants’, and provide a context for interaction with a business capability and the business facts about a business domain. When consistently modeled, they become the backbone of a self-service real-time federated data platform: a rich catalog of stable, coherent and composable APIs.

A REST model will describe a business resource, and how client systems interact with it. It will detail paths, methods and response types. It is a refinement and/or abstraction of the domain data model with a focus on interoperability.

“REST provides a set of architectural constraints that, when applied as a whole, emphasizes scalability of component interactions, generality of interfaces, independent deployment of components” — Fielding, R.T. 2000, Representational State Transfer (REST)

Business resource APIs should strive to be ‘developer-empathetic’ (focused on usability and painless integration), however a System-of-Record business service owns the model and the vocabulary, and is always ‘upstream’.

Composability

Microservices architectures and the REST architectural style enable decoupling, self-service and re-use by moving the responsibility for choreography from the resource server to the client. This shift in responsibility allows business systems to build stable, genericised interfaces to their business resources and capabilities, without tight coupling to client systems, which in turn allows client systems to compose data via self-service integration without a blocking dependency on external teams.

Balancing Composability with Cohesion

The key aims of REST model abstraction — composability, cohesion and stability — are concepts that align closely with the Domain Driven Design process of distillation of the core domain and conceptual contours. If the object that represents the business capability aggregate root is overly large and complex, or if the core focus of the business is not evident in the model, it is likely that the domain model requires further refinement.

“A supple design based on a deep model yields a simple set of interfaces that combine logically to make sensible statements in the ubiquitous language, and without the distraction and maintenance burden of irrelevant options.” Evans, E 2003, Domain Driven Design.

Between aggregate root, entities and value objects, the REST model should not lack opportunities for granularity (responsiveness and composability), but rather should be concerned with finding a balance between granularity and cohesive units of business data likely to be of interest to client systems (though not superfluous to their needs). In short, balancing composability with cohesion. Supporting elements may be modeled as sub-resources on their own path.

Sub-Resources

Sub-resources are resources that are existentially dependent (should not exist without the parent, e.g. ‘specification’ does not exist without a ‘product’), are subordinate to the parent (owned by the parent, e.g. ‘address’ belongs to ‘person’), or contain key information about an existentially linked peer resource.

Keeping in mind the “conceptual contours” principle (cohesive divisions), dependent and subordinate objects modeled as sub-resources within the same API specification as the parent provides a number of advantages, including;

  • Readability, clarity
  • Transparent relationship and context, conveyed by the API path, e.g. ‘v1/products/12B34C/specification’
  • Composability (discrete retrieval of sub-resource data, controlling over-fetching)
  • Controlling the impact of changes

Some sub-resources may be independently addressable, and will have their own state-lifecycle and a unique identity (and resource Id) e.g.

/v1/members/12B34C/dependents/98Y76X 

and in some cases...

/v1/members/dependents/98Y76X

In other cases, the sub-resource will represent a value object, and will be addressed as an object, collection or singleton belonging to a resource instance, e.g.

/v1/products/12B34C/specification

The following factors strongly suggest a sub-resource model:

  • Entity data may be managed (POST/GET/PATCH) separately from the parent entity, and subsequent to instantiation of the parent
  • The data (or any more than a summary) is not always of interest to consumers of the parent resource
  • The data is a distinct entity with a 1:n relationship to the parent, i.e. would result in an array of indeterminate size.
  • The data is binary (file, image)

The general consensus is that more than 2 levels of resource identifier in a URL can make APIs difficult to understand and use. If the model calls for something more than /resource/{resourceId}/resource/{resourceId} then reconsider the composition and/or granularity of the model.

Path and naming conventions and patterns are covered in more detail here.

Binary and multi-part content is covered in more detail here

Affordances

“when a significant process or transformation in the domain is not a natural responsibility of an entity or value object”, it makes sense to… “add an operation to the model as a standalone interface declared as a service” — Evans, E 2003, Domain Driven Design.

Significant, synchronously-driven state-lifecycle transitions (as captured in the domain model — e.g. ‘submit’ or ‘cancel’) may warrant a dedicated affordance operation.

The first consideration around ‘command’ affordances is the question of whether the action should rather be driven by an asynchronous business event. For example, a shipment triggered by a payment event. This approach offers the highest degree of decoupling. Event-based triggers are not always applicable however, for instance in a real-time synchronous user-based interaction, when a client system requires a receipt or Id from the action, or when dealing with legacy or proprietary systems.

Synchronous affordance operations are always verbs that describe the action in the context of a resource (or resource collection). The intent of the affordance and its context are then clear. E.g.

/v1/users/98D76C/cart/checkout

/v1/subscriptions/12B34C/cancel

This topic is covered in a little more depth here: The Engine of Application State: Aligning HATEOAS, Affordances and Business Events| Medium

Filtering and Field Selection

Not every client system will be interested in all of the information provided by a business resource API — even if it is modelled around core business data and streamlined for composability. A predictably implemented parameter driven ‘read’ filtering model that includes field and collection filters can reduce over-fetching and enhance composability. E.g.

GET /v1/subscriptions?subscriberId=12B34C&fields=subscriptionId,name

Query Parameters

The use of query parameters to filter a collection of resources based on field values should be broadly supported.

For example, the query parameter “?color=red” will filter the collection of resources for instances with the field “color” that matches the value “red”. Multiple query parameters return the intersection of results.

Multi-value parameters (an array of values), supporting a query such as “?color=red,green” may also be supported. In OpenAPI 3, a query param array may be defined by the “schema” keyword.

parameters:
- in: query
name: color
schema:
type: array
items:
type: string

Fields Parameter

Consider enabling API consumers to control over-fetching by specifying a subset of fields that they would like returned in the response payload in a ‘fields’ query parameter.

Example GET requesting only the applicationId and applicationDate fields in the response:

GET api.myorg.com/v1/applications?status=pending&fields=applicationId,applicationDate
{
"data": [
{
"applicationId": "808877765733",
"applicationDate": "2022-01-01"
},
{
"applicationId": "80851456484",
"applicationDate": "2022-06-01"
}
]
}

A combination of query, sorting and field parameter support provides client applications with a degree of control over the size and content of the response payload, substantially increasing the usability of the API.

Filtering conventions are discussed in more detail here.

Wrap-up

Business resources provide a context for interaction with a business capability and business data. A key aim of a REST model is composability, cohesion and stability, allowing client systems to compose data via self-service integration without a blocking dependency on external teams.

A good REST model will strike a balance between composability and cohesion, providing cohesive units of business data of interest to client systems, though not superfluous to their needs. This may be achieved by modelling supporting elements as sub-resources on their own path, and facilitating parameter-driven queries and field selection.

Related Articles on Medium

--

--

TRGoodwill
API Central

Tim has several years experience in the delivery and evolution of interoperability frameworks and platforms, and currently works out of Berlin for Accenture ASG