AIP-156

Singleton resources

APIs sometimes need to represent a resource where exactly one instance of the resource always exists within any given parent. A common use case for this is for a config object.

Guidance

An API may define singleton resources. A singleton resource must always exist by virtue of the existence of its parent, with one and exactly one per parent.

For example:

message Config {
  option (google.api.resource) = {
    type: "api.googleapis.com/Config"
    pattern: "users/{user}/config"
    singular: "config"
    plural: "configs"
  };

  // additional fields including name
}

The Config singleton would have the following RPCs:

rpc GetConfig(GetConfigRequest) returns (Config) {
  option (google.api.http) = {
    get: "/v1/{name=users/*/config}"
  };
}

rpc UpdateConfig(UpdateConfigRequest) returns (Config) {
  option (google.api.http) = {
    patch: "/v1/{config.name=users/*/config}"
    body: "config"
  };
}
  • Singleton resources must not have a user-provided or system-generated ID; their resource name includes the name of their parent followed by one static-segment.
    • Example: users/1234/config
  • Singleton resources are always singular.
    • Example: users/1234/thing
  • Singleton resource definitions must provide both the singular and plural fields (see above example).
  • Singleton resources may parent other resources.
  • Singleton resources must not define the Create or Delete standard methods. The singleton is implicitly created or deleted when its parent is created or deleted.
  • Singleton resources should define the Get and Update methods, and may define custom methods as appropriate.
    • However, singleton resources must not define the Update method if all fields on the resource are output only.
  • Singleton resources may define the List method, but must implement it according to AIP-159. See the example below.
    • The trailing segment in the path pattern that typically represents the collection should be the plural form of the Singleton resource e.g. /v1/{parent=users/*}/configs.
    • If a parent resource ID is provided instead of the hyphen - as per AIP-159, then the service should return a collection of one Singleton resource corresponding to the specified parent resource.
rpc ListConfigs(ListConfigsRequest) returns (ListConfigsResponse) {
  option (google.api.http) = {
    get: "/v1/{parent=users/*}/configs"
  };
}

message ListConfigsRequest {
  // To list all configs, use `-` as the user id.
  // Formats:
  // * `users/-`
  // * `users/{user}`
  //
  // Note: Specifying an actual user id will return a collection of one config.
  // Use GetConfig instead.
  string parent = 1 [
    (google.api.resource_reference).child_type = "api.googleapis.com/Config"];

  // other standard pagination fields...
}

Rationale

Support for Standard List

While Singleton resources are not directly part of a collection themselves, they can be viewed as part of their parent's collection. The one-to-one relationship of parent-to-singleton means that for every one parent there is one singleton instance, naturally enabling some collection-based methods when combined with the pattern of Reading Across Collections. The Singleton can present as a collection to the API consumer as it is indirectly one based on its parent. Furthermore, presenting the Singleton resource as a pseudo-collection in such methods enables future expansion to a real collection, should a Singleton be found lacking.

Including plural definition

While a Singleton is by definition singular, there are certain cases where a Singleton resource may appear in a plural form e.g., if the service supports Standard List (as defined here). As such, it is better to forward declare the plural form of the Singleton resource type than to not have it when needed.

Changelog

  • 2024-04-15: Singletons must specify singular and plural in resource.
  • 2023-08-10: Add Standard List support.
  • 2023-07-26: Clarified that read-only singletons should not have Update.
  • 2021-11-02: Added an example message and state parent eligibility.
  • 2021-01-14: Changed example from settings to config for clarity.