API Design Guidance: Singletons

Singleton resources represent a single resource instance, rather than a resource collection. This pattern is useful when you do not require a collection of resources for your API. Let’s examine this pattern and how it can be used to simplify an API design.

This is a multi-part series on API design guidance, where we take a look at tricks and hidden troubles in API designs and how to avoid them. While these articles may not be exhaustive, they will serve to identify common patterns and anti-patterns in API design.

The Singleton Resource

Singleton resources may represent a virtual resource for direct interaction of an existing resource instance, e.g. a user’s one and only profile. APIs may also offer nested singleton resources, when there is a one and only one relationship between the parent resource and its child resource, e.g. a user’s preferences.

When you fail to apply the singleton pattern, an API resource may try to follow the typical CRUD pattern but it may not make sense. For example:

  • POST /sales-tax-calculations – trying to fit in a functional operation that doesn’t produce a new resource instance, e.g. ‘calc sales tax’, into CRUD style produces a design smell. It also may be confusing for developers, e.g. “does this save my calculations for later?” Instead, use a functional resource such as GET /calc-sales-tax
  • POST /users/1234/preferences/{preferenceId} – does this mean that a user can have more than one preferences resource? If not, then the typical CRUD pattern fails here

Singleton Design Examples

Below are some common usage patterns for resource singletons:

  • GET /me – Used in place of GET /users/12345, avoiding the need for the consumer to know their own user identifier
  • PUT /users/5678/preferences – used to manage a single preferences resource instance for a specific account. There is only one instance, the identifier isn’t exposed to the client, and the only operations are GET /users/5678/preferences to retrieve them and PUT /users/5678/preferences to update them.

Should Singletons Be Created First?

Singleton resources may already exist without the need to create them, or they may require creation via a POST endpoint. While singleton resources may not offer the full spectrum of CRUD-style lifecycles like their collection-based brethren, they should still adhere to the proper selection of HTTP action verbs that best match the lifecycle necessary. In this case, use a combination of the HTTP POST and PUT methods to support create and update operations.

For singleton resources that are assumed to exist already, use the HTTP PUT method. This would support an upsert pattern, allowing the client to submit a complete representation of a resource at once, while the server determines if the actual operation is a create or update within the backend data store.

Wrap-up

Singletons offer flexibility of managing a single instance of a resource, without the need to force-fit it into the typical CRUD-based pattern. Singleton resources allow us to create “shortcuts” in our API, e.g. GET /me, or to offer a single resource to manage a nested resource such as user preferences. Singletons are quite powerful, just be sure to evaluate the intended usage and avoid them if the resource will need a full CRUD-like lifecycle support in the future as making a singleton resource into a CRUD-based resource is often a breaking change.