AIP-4231
Parsing resource names
In resource-oriented design (AIP-121), resources represent the primary nouns within APIs, and often have resource names (AIP-122). These resource names convey information about the structure and hierarchy of the resource structure in that API. APIs accept these resource names as parameters when retrieving and modifying resources, and when referencing them in other objects. However, users may struggle to piece together resource names to send, and client libraries have the opportunity to make this easier through the use of helper components.
Guidance
Client libraries may provide helper classes or functions to make constructing resource names more straightforward. However, client libraries that choose to implement this feature must always accept the plain strings also, for two reasons:
- An existing API that adds resource descriptor annotations should be able to do so without incurring a breaking change.
- Resource name patterns occasionally evolve, and users need to be able to send and receive resource names that a statically-compiled client library may not yet acknowledge.
Resource messages
A resource in an API always has a message that describes the representation of
that resource in that API. Client library generators are able to recognize
these messages when they are annotated with the google.api.resource
annotation:
// A representation of a Topic in Pub/Sub.
message Topic {
option (google.api.resource) = {
type: "pubsub.googleapis.com/Topic"
pattern: "projects/{project}/topics/{topic}"
};
// name and so on...
}
- The
type
field provides the unified resource type name.- Client libraries should name their helper component based on this value.
- The universal resource type usually (but not always) ends with a name that matches the name of the message.
- The
pattern
field provides the structure of this resource type's names.- The components in braces represent variable substitutions. Client libraries implementing this feature must accept variables based on these names when building resource name strings.
- Variable substitution names are usually specified in
snake_case
, but this is not guaranteed. Client libraries should be able to accept any annotation that uses any coherent case system. - Patterns are usually slash-separated, but this is not guaranteed. Client libraries should use string interpolation to piece together the resource name.
- The defining message is expected to contain a field called
name
, which is the field holding the resource name.- APIs are able to override the name field's name by setting the
name_field
property on thegoogle.api.resource
annotation. - Code generators should fail with an error if a message is annotated as
a resource and has no name field (either the default of
name
or the field provided in thename_field
property of the annotation). Code generators should also fail with an error if the field is not a string).
- APIs are able to override the name field's name by setting the
Multi-pattern resources
Occasionally, a resource may have more than one pattern. The common case for
this is when a resource can live under more than one parent type. In this
situation, the pattern
field on the annotation can be specified more than
once:
message LogEntry {
option (google.api.resource) = {
type: "logging.googleapis.com/Log"
pattern: "projects/{project}/logs/{log}"
pattern: "organizations/{organization}/logs/{log}"
pattern: "folders/{folder}/logs/{log}"
pattern: "billingAccounts/{billing_account}/logs/{log}"
};
// name and so on...
}
If necessary, client libraries may create a separate helper component for each pattern, and may provide a rollup component.
Resources without messages
Occasionally, a resource may be implicitly defined by an API service, but not have an explicit message representing that resource. (For example, the Firestore API defines databases as a common ancestor to its resources, but does not define a database message.)
In this situation, APIs annotate the resource on the file instead of on a
message, using the google.api.resource_definition
annotation:
option (google.api.resource_definition) = {
type: "firestore.googleapis.com/Database"
pattern: "projects/{project}/databases/{database}"
};
Client library generators implementing this feature must generate the same utility components that would be generated when encountering a resource message.
Referencing other resources
APIs often use resource names for referencing fields defined elsewhere. This is particularly common with the request messages for the standard methods, such as Get and Update; however, resources and other structures use resource name strings as references also.
Client libraries implementing this feature should also provide their helper
components when resources are being referenced. Client libraries are able to
recognize these fields when they are annotated with the
google.api.resource_reference
annotation:
message GetTopicRequest {
// The name of the topic to retrieve.
string name = 1 [(google.api.resource_reference) = {
type: "pubsub.googleapis.com/Topic"
}];
}
The resource reference references the unified resource type name.
Some methods also refer to the parent of a type, and in situations where
there are multiple parents, it is repetitive and error-prone to refer to each
individual parent type. In these situations, API producers specify child_type
rather than type
:
message ListLogEntriesRequest {
// The collection of log entries to list.
string parent = 1 [(google.api.resource_reference) = {
child_type: "logging.googleapis.com/Log"
}];
}
In this situation, client library generators implementing this feature must
derive the set of parent resources from the child type. Client library
generators must fail with an error if both type
and child_type
are
provided.
Referencing an arbitrary resource
Occasionally, a field may reference an arbitrary resource. In this case, APIs
use the special value *
in their resource reference.
message GetIamPolicyRequest {
string resource = 1 [(google.api.resource_reference) = {
type: "*"
}];
}
In this situation, client library generators implementing this feature may provide a generic utility class or function to address that resource name.
Complex resource ID path segments
Warning: Complex resource ID path segments should not generally be used in new APIs. AIP-124 contains advice on handling many-to-many associations.
Resource patterns may contain resource ID path segments which contain multiple pattern variables separated by a variable separator:
message FeedItemTarget {
option (google.api.resource) = {
type: "googleads.googleapis.com/FeedItemTarget"
pattern: "customers/{customer}/feedItemTargets/{feed}~{feed_item}"
};
// name and other fields...
}
This is only used when the resource ID is naturally in multiple parts and it is useful for the user to be able to manipulate the separate ID parts.
- A variable separator is one character long, and must only one of:
_
,-
,.
,~
(underscore, hyphen, period, tilde). - A variable separator must not appear before the first pattern variable or after the last pattern variable.
Backwards compatibility
Client libraries implementing helper components for resources must conform to the following backwards-compatibility expectations:
- The addition of a
google.api.resource
annotation on an existing message must be a backwards-compatible change. - An existing resource must be able to add new patterns (including the "*"
wildcard pattern) without breaking changes as long as the following
conditions are met:
- New patterns must always be appended to the list.
- New patterns must use a distinct sequence of collection identifiers (see AIP-122) compared with all existing patterns within this resource.
- The identifiers within the pattern variables are final - they must not be changed. These identifiers are used in the surface of generated client libraries.
- The addition of a
google.api.resource_reference
annotation on an existing field must be a backwards-compatible change. - Changing a
google.api.resource_reference
fromchild_type
totype
must be a backwards-compatible change when thechild_type
referenced has a singlepattern
and the newly referencedtype
is the matching parent resourcepattern
(see the Referencing other resources section for more info). - For references that appear in a request, changing from
type
tochild_type
must be a backwards-compatible change when the resourcepattern
originally referenced via thetype
is included in the set of possible resourcepattern
s derived throughchild_type
resolution (see the above Multi-pattern resources and Referencing other resources sections for more examples).
Note: The ORIGINALLY_SINGLE_PATTERN
and FUTURE_MULTI_PATTERN
flags are
deprecated, and must not be used.
Further reading
- For more on resource names and patterns, see AIP-122.
- For more on unified resource types, see AIP-123.
Changelog
- 2023-03-25: Include compatibility guidance for
type
andchild_type
. - 2022-10-28: Pattern variables are considered final
- 2020-09-14: Disallow simultaneous use of both
type
andchild_type
. - 2020-05-14: Added complex resource ID path segments.
- 2020-05-07: Updated backwards compatibility guidance.
- 2019-09-16: Added guidance for resources without messages.