| Resource names | |
|---|---|
| Number | 122 |
| Permalink | google.aip.dev/122 |
| State | Approved |
| Created | 2019-01-26 |
| Updated | 2019-01-26 |
AIP-122
Resource names
Most APIs exposeresources (their primary nouns) which users are able tocreate, retrieve, and manipulate. Additionally, resources arenamed: eachresource has a unique identifier that users use to reference that resource, andthese names are what users shouldstore as the canonical names for theresources.
Guidance
All resource names defined by an APImust be unique within that API. (Seethe section onfull resource names below for moreinformation on referring to resources across APIs.)
Resource names are formatted according to theURI path schema, but withoutthe leading slash:
publishers/123/books/les-miserables users/vhugo1802- Resource name componentsshould usually alternate between collection identifiers (example:
publishers,books,users) and resource IDs (example:123,les-miserables,vhugo1802). - Resource namesmust use the
/character to separate individual segments of the resource name.- Non-terminal segments of a resource namemust not contain a
/character. - The terminal segment of a resource nameshould not contain a
/character.
- Non-terminal segments of a resource namemust not contain a
- Resource namesshould only use characters available in DNS names, as defined byRFC-1123.
- Additionally, resource IDsshould not use upper-case letters.
- If additional characters are necessary, resource namesshould not use characters that require URL-escaping, or characters outside of ASCII.
- If Unicode characters can not be avoided, resource namesmust be stored in Normalization Form C (seeAIP-210).
- Resourcesmust expose a
namefield that contains its resource name.- Resourcesmay provide the resource ID as a separate field (e.g.
book_id). This fieldmust apply theOUTPUT_ONLYfield behavior classification. - Resourcesmay expose a separate, system-generated unique ID field(
uid). This fieldmust apply theOUTPUT_ONLYfield behavior classification. - Resourcesmust not expose tuples, self-links, or other forms of resource identification.
- All ID fieldsshould be strings.
- Resourcesmay provide the resource ID as a separate field (e.g.
Note: Resource names as described here are used within the scope of asingle API (or else in situations where the owning API is clear from thecontext), and are only required to be unique within that scope. For thisreason, they are sometimes calledrelative resource names to distinguish themfromfull resource names (discussed below).
Collection identifiers
The collection identifier segments in a resource namemust be the pluralform of the noun used for the resource. (For example, a collection ofPublisher resources is calledpublishers in the resource name.)
- Collection identifiersmust be concise American English terms.
- Collection identifiersmust be in
camelCase. - Collection identifiersmust begin with a lower-cased letter and contain only ASCII letters and numbers (
/[a-z][a-zA-Z0-9]*/). - Collection identifiersmust 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 segmentsmust not "coin" words by adding "s" in such cases (e.g, avoid "infos").
- Within any given single resource name, collection identifiersmust be unique. (e.g.
people/xyz/people/abcis invalid)
Nested collections
If a resource name contains multiple levels of a hierarchy, and a parentcollection's name is used as a prefix for the child resource's name, the childcollection's namemay omit the prefix. For example, given a collection ofUserEvent resources that would normally be nested underneathusers:
users/vhugo1802/userEvents/birthday-dinner-226An APIshould use the less-redundant form:
users/vhugo1802/events/birthday-dinner-226In this situation, themessage andresource type are still calledUserEvent; only the collection and resource identifiers in the pattern(s) are shortened. Since theresource type is not shortened, thesingular andplural are similarlynot 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 thismust follow this format consistentlythroughout all of itspattern entries defined and anywhere else theresource is referenced in the API, or else not at all.
Resource ID segments
A resource ID segment identifies the resource within its parent collection. Inthe resource namepublishers/123/books/les-miserables,123 is the resourceID for the publisher, andles-miserables is the resource ID for the book.
- If resource IDs are user-specified, the APImust document allowed formats. User-specified resource IDsshould conform toRFC-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 IDsshould restrict letters to lower-case (
^[a-z]([a-z0-9-]{0,61}[a-z0-9])?$). - Characters outside of ASCIIshould not be permitted; however, if Unicode characters are necessary, APIsmust follow guidance inAIP-210.
- Additionally, user-specified resource IDsshould restrict letters to lower-case (
- If resource IDs are not user-settable, the APIshould document the basic format, and any upper boundaries (for example, "at most 63 characters").
- For more information, see thecreate standard method.
Resource ID aliases
It is sometimes valuable to provide an alias for common lookup patterns forresource IDs. For example, an API withusers at the top of its resourcehierarchy may wish to provideusers/me as a shortcut for retrievinginformation for the authenticated user.
APIsmay provide programmatic aliases for common lookup patterns. However,all data returned from the APImust use the canonical resource name.
Full resource names
In most cases, resource names are used within a single API only, or else theyare 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 anarbitrary API. In this situation, the serviceshould use thefull resourcename, a schemeless URI with the owningAPI's service name,followed by the relative resource name:
//library.googleapis.com/publishers/123/books/les-miserables//calendar.googleapis.com/users/vhugo1802Note: The full resource nameshould not be used for cross-APIreferences where the owning API is clear; it is only used if a field refers toresources in multiple APIs where ambiguity is possible.
Resource URIs
The full resource name is a schemeless URI, but slightly distinct from the fullURIs we use to access a resource. The latter includes the protocol(HTTPS), the API version, and the specificservice endpointto target:
https://library.googleapis.com/v1/publishers/123/books/les-miserableshttps://calendar.googleapis.com/v3/users/vhugo1802The version is not included in the full resource name because the full resourcename is expected to persist from version to version. Even though the APIsurface may change between major versions, multiple major versions of the sameAPI are expected to use the same underlying data.
Note: The correlation between the full resource name and the service'sendpoint is by convention. In particular, one service is able to have multipleendpoints (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 fieldshould be the resource name,whichmust be of typestring andmust be calledname for theresource name. The messageshould include agoogle.api.resourceannotation declaring the type (seeAIP-123 for more on this).
// A representation of a book in the library.messageBook{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}stringname=1[(google.api.field_behavior)=IDENTIFIER];// Other fields...}When defining a method that retrieves or acts on an already-existing resource(such asGetBook orArchiveBook), the first field of the request messageshould be the resource name, whichmust be of typestring andmust be calledname for the resource name. The fieldshould also beannotated with thegoogle.api.resource_reference annotation, referencing theresource type (AIP-123).
// Request message for ArchiveBookmessageArchiveBookRequest{// The book to archive.// Format: publishers/{publisher}/books/{book}stringname=1[(google.api.field_behavior)=REQUIRED,(google.api.resource_reference)={type:"library.googleapis.com/Book"}];// Other fields...}Note: Fieldsmust not be calledname except for this purpose. Forother use cases, either use a different term or prepend an adjective (forexample:display_name).
Fields representing a resource's parent
When defining a method that retrieves resources from a collection or adds a newresource to a collection (such asListBooks orCreateBook), the first fieldof the request messageshould be of typestring andshould be calledparent for the resource name of the collection. Theparent fieldshouldalso be annotated with thegoogle.api.resource_reference annotation,referencing the parent's resource type (AIP-123).
// Request message for ListBooks.messageListBooksRequest{// The publisher to list books from.// Format: publishers/{publisher_id}stringparent=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, theparent fieldshouldbe annotated with thechild_type key ongoogle.api.resource_referenceinstead:
// Request message for ListBooks.messageListBooksRequest{// The parent to list books from.// Format:// - publishers/{publisher_id}// - authors/{author_id}stringparent=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: Fieldsshould not be calledparent except for this purpose. Forother use cases, use a synonymous term if possible.
Fields representing another resource
When a field represents another resource, the fieldshould be of typestring and accept the resource name of the other resource. The field nameshould be equivalent to the corresponding message's name in snake case.
- Field namesmay include a leading adjective if appropriate (such as
string dusty_book). - Field namesshould not use the
_namesuffix unless the field would be ambiguous without it (e.g.,crypto_key_name) - Fields representing another resourceshould provide the
google.api.resource_referenceannotation with the resource type being referenced. - If using the resource name is not possible and using the ID component alone isstrictly necessary, the fieldshould use an
_idsuffix (e.g.shelf_id).
The fieldshould not be of typemessage using themessage thatimplements 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 theAIP-162 revisions pattern.
Example of a resource reference:
// A representation of a book in a library.messageBook{option(google.api.resource)={type:"library.googleapis.com/Book"pattern:"publishers/{publisher}/books/{book}"};// Name of the book.// Format is `publishers/{publisher}/books/{book}`stringname=1[(google.api.field_behavior)=IDENTIFIER];// The shelf where the book currently sits.// Format is `shelves/{shelf}`.stringshelf=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 resourceIDs to identify a resource, we'd actually need use a resource-specific tuple toreliably identify it, such as(bucket, object) or(user, album, photo). Thiscreates 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 onname
The concept of resource names is not a new one, and is formalized in UniformResource Names (URN) in conjunction with Uniform Resource Identifiers (URI) andUniform Resource Locators (URL). Considering that the term "name" is so heavilyoverloaded in general, usage outside of a very well-defined meaning would beconfusing for developers. So, the field namename is reserved in the contextof AIP-compliant APIs so as to eliminate any confusion with resource names, andforce 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 resourceis 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 bypreventing resource data duplication, and forcing the owning service to beinvolved in the resolution of the reference (via Standard Methods), guaranteeingisolation of logical concerns per-resource.
History
Disallowing UUIDs in user-specified IDs
As part of an effort to make APIs more declarative-friendly, APIs were requiredto allow user-specified resource ID on creation. As part of this, a supportingfieldstring uid containing a UUID was also encouraged. Guidance was thenadded to discourage theuser-specified resource ID from being a UUID oreven resembling one.
Ostensibly, the fact thatuid contained a service-generated UUID motivatedthis restriction on the user-specified resource ID, forcing the user-specifiedresource ID to be a more "meaningful" value. However, we no longer saw value inthis requirement, hence its removal.
Changelog
- 2025-03-10: Drop guidance disallowing UUID in user-specified ID.
- 2024-10-15: Add some rationale we found for use of
nameas 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_ONLYguidance 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 resourceIDs avoid capital characters, not the entire resourcename.
- 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"
View on GitHub