AIP-122
Resource names
Most APIs expose resources (their primary nouns) which users are able to create, retrieve, and manipulate. Additionally, resources are named: each resource has a unique identifier that users use to reference that resource, and these names are what users should store as the canonical names for the resources.
Guidance
All resource names defined by an API must be unique within that API. (See the section on full resource names below for more information on referring to resources across APIs.)
Resource names are formatted according to the URI path schema, but without the leading slash:
publishers/123/books/les-miserables
users/vhugo1802
- Resource name components should usually alternate between collection
identifiers (example:
publishers
,books
,users
) and resource IDs (example:123
,les-miserables
,vhugo1802
). - Resource names must use the
/
character to separate individual segments of the resource name.- Non-terminal segments of a resource name must not contain a
/
character. - The terminal segment of a resource name should not contain a
/
character.
- Non-terminal segments of a resource name must not contain a
- Resource names should only use characters available in DNS names, as
defined by RFC-1123.
- Additionally, resource IDs should not use upper-case letters.
- If additional characters are necessary, resource names should not use characters that require URL-escaping, or characters outside of ASCII.
- If Unicode characters can not be avoided, resource names must be stored in Normalization Form C (see AIP-210).
- Resources must expose a
name
field that contains its resource name.- Resources may provide the resource ID as a separate field (e.g.
book_id
). This field must apply theOUTPUT_ONLY
field behavior classification. - Resources may expose a separate, system-generated unique ID field
(
uid
). This field must apply theOUTPUT_ONLY
field behavior classification. - Resources must not expose tuples, self-links, or other forms of resource identification.
- All ID fields should be strings.
- Resources may provide the resource ID as a separate field (e.g.
Note: Resource names as described here are used within the scope of a single API (or else in situations where the owning API is clear from the context), and are only required to be unique within that scope. For this reason, they are sometimes called relative resource names to distinguish them from full resource names (discussed below).
Collection identifiers
The collection identifier segments in a resource name must be the plural
form of the noun used for the resource. (For example, a collection of
Publisher
resources is called publishers
in the resource name.)
- Collection identifiers must be concise American English terms.
- Collection identifiers must be in
camelCase
. - Collection identifiers must begin with a lower-cased letter and contain
only ASCII letters and numbers (
/[a-z][a-zA-Z0-9]*/
). - Collection identifiers must be plural.
- In situations where there is no plural word ("info"), or where the singular and plural terms are the same ("moose"), the non-pluralized (singular) form is correct. Collection segments must not "coin" words by adding "s" in such cases (e.g, avoid "infos").
- Within any given single resource name, collection identifiers must be
unique. (e.g.
people/xyz/people/abc
is invalid)
Nested collections
If a resource name contains multiple levels of a hierarchy, and a parent
collection's name is used as a prefix for the child resource's name, the child
collection's name may omit the prefix. For example, given a collection of
UserEvent
resources that would normally be nested underneath users
:
users/vhugo1802/userEvents/birthday-dinner-226
An API should use the less-redundant form:
users/vhugo1802/events/birthday-dinner-226
In this situation, the message and resource type are still called
UserEvent
; only the collection and resource identifiers in the pattern(s) are
shortened. Since the resource type is not shortened, the singular
and
plural
are similarly not shortened.
message UserEvent {
option (google.api.resource) = {
type: "example.googleapis.com/UserEvent"
// Only the collection & resource identfiers in the `pattern` are shortened.
pattern: "projects/{project}/users/{user}/events/{event}"
singular: "userEvent"
plural: "userEvents"
};
string name = 1;
}
Note: APIs wishing to do this must follow this format consistently
throughout all of its pattern
entries defined and anywhere else the
resource is referenced in the API, or else not at all.
Resource ID segments
A resource ID segment identifies the resource within its parent collection. In
the resource name publishers/123/books/les-miserables
, 123
is the resource
ID for the publisher, and les-miserables
is the resource ID for the book.
- If resource IDs are user-specified, the API must document allowed
formats. User-specified resource IDs should conform to RFC-1034;
which restricts to letters, numbers, and hyphen, with the first character
a letter, the last a letter or a number, and a 63 character maximum.
- Additionally, user-specified resource IDs should restrict letters to
lower-case (
^[a-z]([a-z0-9-]{0,61}[a-z0-9])?$
). - Characters outside of ASCII should not be permitted; however, if Unicode characters are necessary, APIs must follow guidance in AIP-210.
- User-specified IDs should not be permitted to be a UUID (or any value that syntactically appears to be a UUID).
- Additionally, user-specified resource IDs should restrict letters to
lower-case (
- If resource IDs are not user-settable, the API should document the basic format, and any upper boundaries (for example, "at most 63 characters").
- For more information, see the create standard method.
Resource ID aliases
It is sometimes valuable to provide an alias for common lookup patterns for
resource IDs. For example, an API with users
at the top of its resource
hierarchy may wish to provide users/me
as a shortcut for retrieving
information for the authenticated user.
APIs may provide programmatic aliases for common lookup patterns. However, all data returned from the API must use the canonical resource name.
Full resource names
In most cases, resource names are used within a single API only, or else they
are used in contexts where the owning API is clear (for example,
string pubsub_topic
).
However, sometimes it is necessary for services to refer to resources in an arbitrary API. In this situation, the service should use the full resource name, a schemeless URI with the owning API's service name, followed by the relative resource name:
//library.googleapis.com/publishers/123/books/les-miserables
//calendar.googleapis.com/users/vhugo1802
Note: The full resource name should not be used for cross-API references where the owning API is clear; it is only used if a field refers to resources in multiple APIs where ambiguity is possible.
Resource URIs
The full resource name is a schemeless URI, but slightly distinct from the full URIs we use to access a resource. The latter includes the protocol (HTTPS), the API version, and the specific service endpoint to target:
https://library.googleapis.com/v1/publishers/123/books/les-miserables
https://calendar.googleapis.com/v3/users/vhugo1802
The version is not included in the full resource name because the full resource name is expected to persist from version to version. Even though the API surface may change between major versions, multiple major versions of the same API are expected to use the same underlying data.
Note: The correlation between the full resource name and the service's endpoint is by convention. In particular, one service is able to have multiple endpoints (example use cases include regionalization, MTLS, and private access), and the full resource name does not change between these.
Fields representing resource names
When defining a resource, the first field should be the resource name,
which must be of type string
and must be called name
for the
resource name. The message should include a google.api.resource
annotation declaring the type (see AIP-123 for more on this).
// A representation of a book in the library.
message Book {
option (google.api.resource) = {
type: "library.googleapis.com/Book"
pattern: "publishers/{publisher}/books/{book}"
};
// The resource name of the book.
// Format: publishers/{publisher}/books/{book}
string name = 1 [(google.api.field_behavior) = IDENTIFIER];
// Other fields...
}
When defining a method that retrieves or acts on an already-existing resource
(such as GetBook
or ArchiveBook
), the first field of the request message
should be the resource name, which must be of type string
and
must be called name
for the resource name. The field should also be
annotated with the google.api.resource_reference
annotation, referencing the
resource type (AIP-123).
// Request message for ArchiveBook
message ArchiveBookRequest {
// The book to archive.
// Format: publishers/{publisher}/books/{book}
string name = 1 [
(google.api.field_behavior) = REQUIRED,
(google.api.resource_reference) = {
type: "library.googleapis.com/Book"
}];
// Other fields...
}
Note: Fields must not be called name
except for this purpose. For
other use cases, either use a different term or prepend an adjective (for
example: display_name
).
Fields representing a resource's parent
When defining a method that retrieves resources from a collection or adds a new
resource to a collection (such as ListBooks
or CreateBook
), the first field
of the request message should be of type string
and should be called
parent
for the resource name of the collection. The parent
field should
also be annotated with the google.api.resource_reference
annotation,
referencing the parent's resource type (AIP-123).
// Request message for ListBooks.
message ListBooksRequest {
// The publisher to list books from.
// Format: publishers/{publisher_id}
string parent = 1 [(google.api.resource_reference) = {
type: "library.googleapis.com/Publisher"
}];
// Other fields (e.g. page_size, page_token, filter, etc.)...
}
If there is more than one possible parent type, the parent
field should
be annotated with the child_type
key on google.api.resource_reference
instead:
// Request message for ListBooks.
message ListBooksRequest {
// The parent to list books from.
// Format:
// - publishers/{publisher_id}
// - authors/{author_id}
string parent = 1 [
(google.api.field_behavior) = REQUIRED,
(google.api.resource_reference) = {
child_type: "library.googleapis.com/Book"
}];
// Other fields (e.g. page_size, page_token, filter, etc.)...
}
Note: Fields should not be called parent
except for this purpose. For
other use cases, use a synonymous term if possible.
Fields representing another resource
When a field represents another resource, the field should be of type
string
and accept the resource name of the other resource. The field name
should be equivalent to the corresponding message's name in snake case.
- Field names may include a leading adjective if appropriate (such as
string dusty_book
). - Field names should not use the
_name
suffix unless the field would be ambiguous without it (e.g.,crypto_key_name
) - Fields representing another resource should provide the
google.api.resource_reference
annotation with the resource type being referenced. - If using the resource name is not possible and using the ID component alone is
strictly necessary, the field should use an
_id
suffix (e.g.shelf_id
).
The field should not be of type message
using the message
that
implements the resource, except for one of following conditions:
- The API is internal-only, has tight lifecycle relationships, and has a permission model that enables inherited access to embedded resources.
- The embedding of the resource is done as part of the AIP-162 revisions pattern.
Example of a resource reference:
// A representation of a book in a library.
message Book {
option (google.api.resource) = {
type: "library.googleapis.com/Book"
pattern: "publishers/{publisher}/books/{book}"
};
// Name of the book.
// Format is `publishers/{publisher}/books/{book}`
string name = 1 [(google.api.field_behavior) = IDENTIFIER];
// The shelf where the book currently sits.
// Format is `shelves/{shelf}`.
string shelf = 2 [(google.api.resource_reference) = {
type: "library.googleapis.com/Shelf"
}];
// Other fields...
}
Further reading
Rationale
Using names instead of IDs
For any large system, there are many kinds of resources. To use simple resource
IDs to identify a resource, we'd actually need use a resource-specific tuple to
reliably identify it, such as (bucket, object)
or (user, album, photo)
. This
creates several issues:
- Developers have to understand and remember such anonymous tuples.
- Passing tuples is generally harder than passing strings.
- Centralized infrastructures, such as logging and access control systems, don't understand specialized tuples.
- Specialized tuples limit API design flexibility, such as providing reusable API interfaces. For example, Long Running Operations can work with many other API interfaces because they use flexible resource names.
Standardizing on name
The concept of resource names is not a new one, and is formalized in Uniform
Resource Names (URN) in conjunction with Uniform Resource Identifiers (URI) and
Uniform Resource Locators (URL). Considering that the term "name" is so heavily
overloaded in general, usage outside of a very well-defined meaning would be
confusing for developers. So, the field name name
is reserved in the context
of AIP-compliant APIs so as to eliminate any confusion with resource names, and
force other would be "name" fields to use a more specific field name.
Disallow embedding of resources
Using a resource message directly as the type of a field within another resource is problematic for a number of reasons, which are as follows:
- Complicates the resource lifecycle: If the dependency resource is deleted, what happens to the embedded reference in the dependent resource? Data retention and clean up operations will be significantly complicated.
- Bypasses permissions: If every resource has its own set of permissions, a user with read permission on the dependent resource that doesn't have the same permission on the dependency resource suddenly cannot see the full resource.
- Tightly couples resources in all aspects: Changing the requirements in the schema, permissions, or otherwise for either resource impacts the other, significantly increasing complexity of roll outs.
Referencing by name, as is recommended, eliminates all of this complexity by preventing resource data duplication, and forcing the owning service to be involved in the resolution of the reference (via Standard Methods), guaranteeing isolation of logical concerns per-resource.
Changelog
- 2024-10-15: Add some rationale we found for use of
name
as a field and instead of IDs as an identifier. - 2024-06-14: Clarify resource annotation shortening rules for nested collections.
- 2023-09-19: Prohibit duplicate collection identifiers.
- 2023-09-01: Add a clause that allows embedding for revision resource messages.
- 2023-08-10: Explicitly disallow embedding resource messages in a resource.
- 2023-03-24: Correction: full resource name contains the service name rather than the service endpoint
- 2023-03-17: Add
OUTPUT_ONLY
guidance for resource ID fields. - 2020-10-06: Added declarative-friendly guidance, and tightened character set restrictions.
- 2020-10-05: Clarified when full resource names are used.
- 2020-05-19: Clarified that resource IDs avoid capital characters, not the entire resource name.
- 2020-04-27: Tighten the restriction on valid characters.
- 2019-12-05: Added guidance for resource annotations.
- 2019-08-01: Changed the examples from "shelves" to "publishers", to present a better example of resource ownership. Also changed the final example from a Pub/Sub example to the usual Book example.
- 2019-07-30: Changed the nested collection brevity suggestion from "may" to "should"