From 02069079e33e9b6887906cb3998ff8a627ace917 Mon Sep 17 00:00:00 2001 From: Richard Frankel Date: Wed, 11 Oct 2023 20:48:45 -0500 Subject: [PATCH 01/12] Adopt AEP-122: Resouce paths This is an adaptation of Roblox's AIP-122, which is an adaptation of Google's AIP-122. This primary difference from Google's AIP-122 is the change from "name" to "path" for the key concept defined by the AEP. Some notes on this PR: * This PR currently has protobuf-only guidance. If the content is generally acceptable to the working group, I'm happy to add the relevant OAS tabs. * The proposed new numbering scheme is ignored, because there are existing AEPs that don't use it. If and when we change the numbering scheme, a separate PR will be required anyway. * The PR uses apis.example.com/ (Roblox pattern) rather than ".exampleapis.com" (Google pattern). No strong feeling about this either way. --- aep/general/0122/aep.md | 318 ++++++++++++++++++++++++++++++++++++++ aep/general/0122/aep.yaml | 8 + 2 files changed, 326 insertions(+) create mode 100644 aep/general/0122/aep.md create mode 100644 aep/general/0122/aep.yaml diff --git a/aep/general/0122/aep.md b/aep/general/0122/aep.md new file mode 100644 index 00000000..e21e7a7e --- /dev/null +++ b/aep/general/0122/aep.md @@ -0,0 +1,318 @@ +# Resource paths + +Most APIs expose _resources_ (their primary nouns) which users are able to +create, retrieve, and manipulate. Additionally, resources have _paths_: each +resource has a unique identifying path that users use to reference that +resource, and these paths are what users should _store_ as the canonical path +for the resources. + +## Guidance + +All resource paths defined by an API **must** be unique within that API. (See +the section on [full resource paths](#full-resource-paths) below for more +information on referring to resources across APIs.) + +Resource paths are formatted according to the [URI path schema][], but without +the leading slash: + + publishers/123/books/les-miserables + users/vhugo1802 + +- Resource path components **should** usually alternate between collection + identifiers (example: `publishers`, `books`, `users`) and resource IDs + (example: `123`, `les-miserables`, `vhugo1802`). +- Resource paths **must** use the `/` character to separate individual segments + of the resource path. + - Non-terminal segments of a resource path **must not** contain a `/` + character. + - The terminal segment of a resource path **should not** contain a `/` + character. +- Resource paths **should** only use characters available in DNS names, as + defined by [RFC-1123](https://tools.ietf.org/html/rfc1123). + - Additionally, resource IDs **should not** use upper-case letters. + - If additional characters are necessary, resource paths **should not** use + characters that require URL-escaping, or characters outside of ASCII. + - If Unicode characters can not be avoided, resource paths **must** be stored + in Normalization Form C (see [AIP-210][]). +- Eacg resource **must** expose a `path` field that contains its resource path. + - Resources **may** provide the resource ID, i.e. the last segment of the + path, as a separate field named `id`. + - Resources **may** expose a separate, system-generated unique ID field + (`uid`). + - Resources **must not** expose tuples, self-links, or other forms of + resource identification. + - All ID fields **must** be strings. + +**Note:** Resource paths 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 paths_ to distinguish them +from _full resource paths_ (discussed below). + +[aip-210]: ./0210.md +[uri path schema]: https://datatracker.ietf.org/doc/html/rfc3986#appendix-A + +### Collection identifiers + +The collection identifier segments in a resource path **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 path.) + +- Collection identifiers **must** be concise American English terms. +- Collection identifiers **must** be in `kebab-case`. +- Collection identifiers **must** begin with a lower-cased letter and contain + only lower-case ASCII letters, numbers. and hyphens (`/[a-z][a-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"). + +#### Nested collections + +If a resource path contains multiple levels of a hierarchy, and a parent +collection's path is used as a prefix for the child resource's path, the child +collection's path **may** omit the prefix. For example, given a collection of +`UserEvent` resources that would normally be nested underneath `users`: + +``` +users/vhugo1802/user-events/birthday-dinner-226/user-event-guests/123 +``` + +An API **may** use the less-redundant form: + +``` +users/vhugo1802/events/birthday-dinner-226/guests/123 +``` + +In this situation, the _message_ is still called `UserEvent` or +`UserEventGuest`; only the collection name is shortened. + +**Note:** APIs wishing to do this **must** follow this format consistently +throughout the API, or else not at all. + +### Resource ID segments + +A resource ID segment identifies the resource within its parent collection. In +the resource path `publishers/123/books/les-miserables`, `123` is the resource +ID for the publisher, and `les-miserables` is the resource ID for the book. + +- Resource IDs **may** be either always set by users (required on resource + creation), optionally set by users (optional on resource creation, + server-generated if unset), or never set by users (not accepted at resource + creation). They **should** be immutable once created. + - If resource IDs are user-settable, the API **must** document allowed + formats. User-settable 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-settable 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-settable IDs **should not** be permitted to be a UUID (or any value + that syntactically appears to be a UUID). + - 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. + +[aip-128]: ./0128.md +[create]: ./0133.md#user-specified-ids +[rfc-1034]: https://tools.ietf.org/html/rfc1034 + +### 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 path. + +### Full resource paths + +In most cases, resource paths 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 +path_, a schemeless URI with the owning API's service endpoint, followed by the +relative resource path: + +``` +//apis.example.com/library/publishers/123/books/les-miserables +//apis.example.com/calendar/users/vhugo1802 +``` + +**Note:** The full resource path **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 path is a schemeless URI, but slightly distinct from the full +URIs we use to access a resource. The latter adds two components: the protocol +(HTTPS) and the API version: + +``` +https://apis.example.com/library/v1/publishers/123/books/les-miserables +https://apis.example.com/calendar/v3/users/vhugo1802 +``` + +The version is not included in the full resource path because the full resource +path 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 path and the service's +hostname is by convention. In particular, one service is able to have multiple +hostnames (example use cases include regionalization or staging environments), +and the full resource path does not change between these. + +### Fields representing resource paths + +When defining a resource, the first field **should** be the resource path, +which **must** be of type `string` and **must** be called `path` for the +resource path. The message **should** include a `google.api.resource` +annotation declaring the type (see [AIP-123][] for more on this). + +```proto +// A representation of a book in the library. +message Book { + option (google.api.resource) = { + type: "apis.example.com/library/Book" + pattern: "publishers/{publisher}/books/{book}" + }; + + // The resource path of the book. + // Format: publishers/{publisher}/books/{book} + string path = 1; + + // 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 path, which **must** be of type `string` and +**must** be called `path` for the resource path. The field **should** also be +annotated with the `google.api.resource_reference` annotation, referencing the +resource type ([AIP-123][]). + +```proto +// Request message for ArchiveBook +message ArchiveBookRequest { + // The book to archive. + // Format: publishers/{publisher}/books/{book} + string path = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { + type: "apis.example.com/library/Book" + }]; + + // Other fields... +} +``` + +**Note:** Fields **must not** be called `path` except for this purpose. For +other use cases, either use a different term or prepend an adjective (for +example: `file_path`). + +[aip-123]: ./0123.md + +### 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 path 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][]). + +```proto +// Request message for ListBooks. +message ListBooksRequest { + // The publisher to list books from. + // Format: publishers/{publisher_id} + string parent = 1 [(google.api.resource_reference) = { + type: "apis.example.com/library/Publisher" + }]; + + // Other fields (e.g. max_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: + +```proto +// 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: "apis.example.com/library/Book" + }]; + + // Other fields (e.g. max_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 referencing a resource path for a different resource, the field **should** +be of type `string` for the resource path, and 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 `_path` suffix unless the field would be + ambiguous without it (e.g., `crypto_key_path`) +- Fields representing another resource **should** provide the + `google.api.resource_reference` annotation with the resource type being + referenced. + +```proto +// A representation of a book in a library. +message Book { + option (google.api.resource) = { + type: "apis.example.com/library/Book" + pattern: "publishers/{publisher}/books/{book}" + }; + + // Path of the book. + // Format is `publishers/{publisher}/books/{book}` + string path = 1; + + // The shelf where the book currently sits. + // Format is `shelves/{shelf}`. + string shelf = 2 [(google.api.resource_reference) = { + type: "apis.example.com/library/Shelf" + }]; + + // Other fields... +} +``` + +**Note:** When referring to other resources in this way, we use the resource +path as the value, not just the ID component. Services **should** use the +resource path to reference resources when possible. If using the ID component +alone is strictly necessary, the field **should** use an `_id` suffix (e.g. +`shelf_id`). + +## Further reading + +- For evolving resource paths over time, see + [AIP-180](./0180.md#changing-resource-paths). +- For resource types, see [AIP-123][]. diff --git a/aep/general/0122/aep.yaml b/aep/general/0122/aep.yaml new file mode 100644 index 00000000..9c506aa3 --- /dev/null +++ b/aep/general/0122/aep.yaml @@ -0,0 +1,8 @@ +--- +id: 122 +state: approved +created: 2023-10-11 +placement: + category: resource-design + order: 20 +redirect_from: /resource-paths From db360b2636f3b60ed090fb4ff10835e69fc7ed60 Mon Sep 17 00:00:00 2001 From: Richard Frankel Date: Thu, 12 Oct 2023 17:48:41 -0400 Subject: [PATCH 02/12] Update aep/general/0122/aep.md Co-authored-by: Yusuke Tsutsumi --- aep/general/0122/aep.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aep/general/0122/aep.md b/aep/general/0122/aep.md index e21e7a7e..20666e9a 100644 --- a/aep/general/0122/aep.md +++ b/aep/general/0122/aep.md @@ -3,7 +3,7 @@ Most APIs expose _resources_ (their primary nouns) which users are able to create, retrieve, and manipulate. Additionally, resources have _paths_: each resource has a unique identifying path that users use to reference that -resource, and these paths are what users should _store_ as the canonical path +resource, and these paths are what users should _store_ as the canonical identifier for the resources. ## Guidance From f905e7faad8b7be13ebb3dfbb6ad912764c46abf Mon Sep 17 00:00:00 2001 From: Richard Frankel Date: Thu, 12 Oct 2023 17:51:25 -0400 Subject: [PATCH 03/12] Update aep/general/0122/aep.md Co-authored-by: Yusuke Tsutsumi --- aep/general/0122/aep.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aep/general/0122/aep.md b/aep/general/0122/aep.md index 20666e9a..09b347fe 100644 --- a/aep/general/0122/aep.md +++ b/aep/general/0122/aep.md @@ -34,7 +34,7 @@ the leading slash: characters that require URL-escaping, or characters outside of ASCII. - If Unicode characters can not be avoided, resource paths **must** be stored in Normalization Form C (see [AIP-210][]). -- Eacg resource **must** expose a `path` field that contains its resource path. +- Each resource **must** expose a `path` field that contains its resource path. - Resources **may** provide the resource ID, i.e. the last segment of the path, as a separate field named `id`. - Resources **may** expose a separate, system-generated unique ID field From 1c6c4470c84cfb96b4d45b2a1c20a455ea6c95df Mon Sep 17 00:00:00 2001 From: Richard Frankel Date: Thu, 12 Oct 2023 17:02:33 -0500 Subject: [PATCH 04/12] Address PR feedback from @toumorokoshi. --- aep/general/0122/aep.md | 169 +++++++++++++++++++--------------------- 1 file changed, 82 insertions(+), 87 deletions(-) diff --git a/aep/general/0122/aep.md b/aep/general/0122/aep.md index 09b347fe..215b7b31 100644 --- a/aep/general/0122/aep.md +++ b/aep/general/0122/aep.md @@ -3,8 +3,8 @@ Most APIs expose _resources_ (their primary nouns) which users are able to create, retrieve, and manipulate. Additionally, resources have _paths_: each resource has a unique identifying path that users use to reference that -resource, and these paths are what users should _store_ as the canonical identifier -for the resources. +resource, and these paths are what users should _store_ as the canonical +identifier for the resources. ## Guidance @@ -15,25 +15,21 @@ information on referring to resources across APIs.) Resource paths are formatted according to the [URI path schema][], but without the leading slash: - publishers/123/books/les-miserables - users/vhugo1802 +publishers/123/books/les-miserables users/vhugo1802 - Resource path components **should** usually alternate between collection identifiers (example: `publishers`, `books`, `users`) and resource IDs (example: `123`, `les-miserables`, `vhugo1802`). - Resource paths **must** use the `/` character to separate individual segments of the resource path. - - Non-terminal segments of a resource path **must not** contain a `/` - character. - - The terminal segment of a resource path **should not** contain a `/` - character. +- Each segment of a resource path **must not** contain a `/` character. - Resource paths **should** only use characters available in DNS names, as defined by [RFC-1123](https://tools.ietf.org/html/rfc1123). - Additionally, resource IDs **should not** use upper-case letters. - If additional characters are necessary, resource paths **should not** use characters that require URL-escaping, or characters outside of ASCII. - If Unicode characters can not be avoided, resource paths **must** be stored - in Normalization Form C (see [AIP-210][]). + in Normalization Form C (see [AEP-210][]). - Each resource **must** expose a `path` field that contains its resource path. - Resources **may** provide the resource ID, i.e. the last segment of the path, as a separate field named `id`. @@ -49,7 +45,7 @@ context), and are only required to be unique within that scope. For this reason, they are sometimes called _relative resource paths_ to distinguish them from _full resource paths_ (discussed below). -[aip-210]: ./0210.md +[aep-210]: ./0210.md [uri path schema]: https://datatracker.ietf.org/doc/html/rfc3986#appendix-A ### Collection identifiers @@ -63,10 +59,10 @@ form of the noun used for the resource. (For example, a collection of - Collection identifiers **must** begin with a lower-cased letter and contain only lower-case ASCII letters, numbers. and hyphens (`/[a-z][a-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"). +- 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"). #### Nested collections @@ -101,23 +97,22 @@ ID for the publisher, and `les-miserables` is the resource ID for the book. creation), optionally set by users (optional on resource creation, server-generated if unset), or never set by users (not accepted at resource creation). They **should** be immutable once created. - - If resource IDs are user-settable, the API **must** document allowed - formats. User-settable 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-settable 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-settable IDs **should not** be permitted to be a UUID (or any value - that syntactically appears to be a UUID). - - 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. - -[aip-128]: ./0128.md +- If resource IDs are user-settable, the API **must** document allowed formats. + User-settable 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-settable 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 + [AEP-210][]. + - User-settable IDs **should not** be permitted to be a UUID (or any value + that syntactically appears to be a UUID). +- 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. + +[aep-128]: ./0128.md [create]: ./0133.md#user-specified-ids [rfc-1034]: https://tools.ietf.org/html/rfc1034 @@ -177,21 +172,21 @@ and the full resource path does not change between these. When defining a resource, the first field **should** be the resource path, which **must** be of type `string` and **must** be called `path` for the resource path. The message **should** include a `google.api.resource` -annotation declaring the type (see [AIP-123][] for more on this). +annotation declaring the type (see [AEP-123][] for more on this). ```proto // A representation of a book in the library. message Book { - option (google.api.resource) = { - type: "apis.example.com/library/Book" - pattern: "publishers/{publisher}/books/{book}" - }; +option (google.api.resource) = { + type: "apis.example.com/library/Book" + pattern: "publishers/{publisher}/books/{book}" +}; - // The resource path of the book. - // Format: publishers/{publisher}/books/{book} - string path = 1; +// The resource path of the book. +// Format: publishers/{publisher}/books/{book} +string path = 1; - // Other fields... +// Other fields... } ``` @@ -200,20 +195,20 @@ When defining a method that retrieves or acts on an already-existing resource **should** be the resource path, which **must** be of type `string` and **must** be called `path` for the resource path. The field **should** also be annotated with the `google.api.resource_reference` annotation, referencing the -resource type ([AIP-123][]). +resource type ([AEP-123][]). ```proto // Request message for ArchiveBook message ArchiveBookRequest { - // The book to archive. - // Format: publishers/{publisher}/books/{book} - string path = 1 [ - (google.api.field_behavior) = REQUIRED, - (google.api.resource_reference) = { - type: "apis.example.com/library/Book" - }]; - - // Other fields... +// The book to archive. +// Format: publishers/{publisher}/books/{book} +string path = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { + type: "apis.example.com/library/Book" + }]; + +// Other fields... } ``` @@ -221,7 +216,7 @@ message ArchiveBookRequest { other use cases, either use a different term or prepend an adjective (for example: `file_path`). -[aip-123]: ./0123.md +[aep-123]: ./0123.md ### Fields representing a resource's parent @@ -230,18 +225,18 @@ 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 path 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][]). +referencing the parent's resource type ([AEP-123][]). ```proto // Request message for ListBooks. message ListBooksRequest { - // The publisher to list books from. - // Format: publishers/{publisher_id} - string parent = 1 [(google.api.resource_reference) = { - type: "apis.example.com/library/Publisher" - }]; +// The publisher to list books from. +// Format: publishers/{publisher_id} +string parent = 1 [(google.api.resource_reference) = { + type: "apis.example.com/library/Publisher" +}]; - // Other fields (e.g. max_page_size, page_token, filter, etc.)... +// Other fields (e.g. max_page_size, page_token, filter, etc.)... } ``` @@ -252,17 +247,17 @@ instead: ```proto // 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: "apis.example.com/library/Book" - }]; - - // Other fields (e.g. max_page_size, page_token, filter, etc.)... +// 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: "apis.example.com/library/Book" + }]; + +// Other fields (e.g. max_page_size, page_token, filter, etc.)... } ``` @@ -286,22 +281,22 @@ equivalent to the corresponding message's name in snake case. ```proto // A representation of a book in a library. message Book { - option (google.api.resource) = { - type: "apis.example.com/library/Book" - pattern: "publishers/{publisher}/books/{book}" - }; - - // Path of the book. - // Format is `publishers/{publisher}/books/{book}` - string path = 1; - - // The shelf where the book currently sits. - // Format is `shelves/{shelf}`. - string shelf = 2 [(google.api.resource_reference) = { - type: "apis.example.com/library/Shelf" - }]; - - // Other fields... +option (google.api.resource) = { + type: "apis.example.com/library/Book" + pattern: "publishers/{publisher}/books/{book}" +}; + +// Path of the book. +// Format is `publishers/{publisher}/books/{book}` +string path = 1; + +// The shelf where the book currently sits. +// Format is `shelves/{shelf}`. +string shelf = 2 [(google.api.resource_reference) = { + type: "apis.example.com/library/Shelf" +}]; + +// Other fields... } ``` @@ -314,5 +309,5 @@ alone is strictly necessary, the field **should** use an `_id` suffix (e.g. ## Further reading - For evolving resource paths over time, see - [AIP-180](./0180.md#changing-resource-paths). -- For resource types, see [AIP-123][]. + [AEP-180](./0180.md#changing-resource-paths). +- For resource types, see [AEP-123][]. From aea4f5ce04e07184aee3099b6694851bc6171045 Mon Sep 17 00:00:00 2001 From: Richard Frankel Date: Wed, 18 Oct 2023 14:45:51 -0500 Subject: [PATCH 05/12] Clarify wording around resource path uniqueness. --- aep/general/0122/aep.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aep/general/0122/aep.md b/aep/general/0122/aep.md index 215b7b31..1fe998a5 100644 --- a/aep/general/0122/aep.md +++ b/aep/general/0122/aep.md @@ -2,9 +2,9 @@ Most APIs expose _resources_ (their primary nouns) which users are able to create, retrieve, and manipulate. Additionally, resources have _paths_: each -resource has a unique identifying path that users use to reference that -resource, and these paths are what users should _store_ as the canonical -identifier for the resources. +resource has a unique (within the API service) identifying path that users use +to reference that resource, and these paths are what users should _store_ as +the canonical identifier for the resources. ## Guidance From cb631aae4ba97410bdb119dfe8f9bb6a1647b616 Mon Sep 17 00:00:00 2001 From: Richard Frankel Date: Mon, 23 Oct 2023 14:24:46 -0500 Subject: [PATCH 06/12] Add information about how to annotate valid ID formats. --- aep/general/0122/aep.md | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/aep/general/0122/aep.md b/aep/general/0122/aep.md index 1fe998a5..b1663397 100644 --- a/aep/general/0122/aep.md +++ b/aep/general/0122/aep.md @@ -97,10 +97,11 @@ ID for the publisher, and `les-miserables` is the resource ID for the book. creation), optionally set by users (optional on resource creation, server-generated if unset), or never set by users (not accepted at resource creation). They **should** be immutable once created. -- If resource IDs are user-settable, the API **must** document allowed formats. - User-settable 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. +- If resource IDs are user-settable, the API **must** document and/or annotate + the field with the allowed formats. User-settable 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-settable 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 @@ -108,6 +109,8 @@ ID for the publisher, and `les-miserables` is the resource ID for the book. [AEP-210][]. - User-settable IDs **should not** be permitted to be a UUID (or any value that syntactically appears to be a UUID). + - Field annotations **should** use [protovalidate][] in protobuf and + `@pattern` with OAS/JSON Schema. - 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. @@ -311,3 +314,7 @@ alone is strictly necessary, the field **should** use an `_id` suffix (e.g. - For evolving resource paths over time, see [AEP-180](./0180.md#changing-resource-paths). - For resource types, see [AEP-123][]. + + +[protovalidate]: https://github.com/bufbuild/protovalidate + From 050af4a8d25c90472458484f359d27663d3d9d7b Mon Sep 17 00:00:00 2001 From: Richard Frankel Date: Mon, 23 Oct 2023 14:26:48 -0500 Subject: [PATCH 07/12] Linkify `pattern`. --- aep/general/0122/aep.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/aep/general/0122/aep.md b/aep/general/0122/aep.md index b1663397..211b571a 100644 --- a/aep/general/0122/aep.md +++ b/aep/general/0122/aep.md @@ -110,7 +110,7 @@ ID for the publisher, and `les-miserables` is the resource ID for the book. - User-settable IDs **should not** be permitted to be a UUID (or any value that syntactically appears to be a UUID). - Field annotations **should** use [protovalidate][] in protobuf and - `@pattern` with OAS/JSON Schema. + [`pattern`][] with OAS/JSON Schema. - 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. @@ -317,4 +317,5 @@ alone is strictly necessary, the field **should** use an `_id` suffix (e.g. [protovalidate]: https://github.com/bufbuild/protovalidate +[`pattern`]: https://json-schema.org/understanding-json-schema/reference/string#regexp From 75d52a36b34aa75126b9b1f9e10aa884e6100842 Mon Sep 17 00:00:00 2001 From: Richard Frankel Date: Tue, 24 Oct 2023 14:07:51 -0400 Subject: [PATCH 08/12] Update aep/general/0122/aep.md Co-authored-by: Yusuke Tsutsumi --- aep/general/0122/aep.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aep/general/0122/aep.md b/aep/general/0122/aep.md index 211b571a..fb87666f 100644 --- a/aep/general/0122/aep.md +++ b/aep/general/0122/aep.md @@ -96,7 +96,7 @@ ID for the publisher, and `les-miserables` is the resource ID for the book. - Resource IDs **may** be either always set by users (required on resource creation), optionally set by users (optional on resource creation, server-generated if unset), or never set by users (not accepted at resource - creation). They **should** be immutable once created. + creation). They **must** be immutable once created. - If resource IDs are user-settable, the API **must** document and/or annotate the field with the allowed formats. User-settable resource IDs **should** conform to [RFC-1034][]; which restricts to letters, numbers, and hyphen, From 136070fa4eb62804850cf492f13f20b006373ed2 Mon Sep 17 00:00:00 2001 From: Richard Frankel Date: Wed, 25 Oct 2023 17:03:35 -0500 Subject: [PATCH 09/12] Address comments from @toumorokoshi. --- aep/general/0122/aep.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/aep/general/0122/aep.md b/aep/general/0122/aep.md index 211b571a..518b8b4a 100644 --- a/aep/general/0122/aep.md +++ b/aep/general/0122/aep.md @@ -17,9 +17,10 @@ the leading slash: publishers/123/books/les-miserables users/vhugo1802 -- Resource path components **should** usually alternate between collection - identifiers (example: `publishers`, `books`, `users`) and resource IDs - (example: `123`, `les-miserables`, `vhugo1802`). +- Resource path components **must** alternate between collection identifiers + (example: `publishers`, `books`, `users`) and resource IDs (example: `123`, + `les-miserables`, `vhugo1802`), _except_ when [singleton resources][] are + present. - Resource paths **must** use the `/` character to separate individual segments of the resource path. - Each segment of a resource path **must not** contain a `/` character. @@ -33,8 +34,6 @@ publishers/123/books/les-miserables users/vhugo1802 - Each resource **must** expose a `path` field that contains its resource path. - Resources **may** provide the resource ID, i.e. the last segment of the path, as a separate field named `id`. - - Resources **may** expose a separate, system-generated unique ID field - (`uid`). - Resources **must not** expose tuples, self-links, or other forms of resource identification. - All ID fields **must** be strings. @@ -47,6 +46,7 @@ from _full resource paths_ (discussed below). [aep-210]: ./0210.md [uri path schema]: https://datatracker.ietf.org/doc/html/rfc3986#appendix-A +[singleton resources]: https://aep.dev/singletons ### Collection identifiers From 3b507409aa103a35727ea5bdba528474d349a1bc Mon Sep 17 00:00:00 2001 From: Richard Frankel Date: Fri, 17 Nov 2023 02:38:25 -0600 Subject: [PATCH 10/12] Fix reference to JSON Schema keywords. --- aep/general/0122/aep.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/aep/general/0122/aep.md b/aep/general/0122/aep.md index 6bf63db1..b9bf39cd 100644 --- a/aep/general/0122/aep.md +++ b/aep/general/0122/aep.md @@ -109,15 +109,18 @@ ID for the publisher, and `les-miserables` is the resource ID for the book. [AEP-210][]. - User-settable IDs **should not** be permitted to be a UUID (or any value that syntactically appears to be a UUID). - - Field annotations **should** use [protovalidate][] in protobuf and - [`pattern`][] with OAS/JSON Schema. + - Field annotations **should** use [protovalidate][] in protobuf and [JSON + Schema keywords][] like [`pattern`][] with OAS/JSON Schema. - 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. + [aep-128]: ./0128.md [create]: ./0133.md#user-specified-ids [rfc-1034]: https://tools.ietf.org/html/rfc1034 +[JSON Schema keywords]: https://swagger.io/docs/specification/data-models/keywords/ + ### Resource ID aliases From e965cea7ab6ac13326de848b8111f9e328bb3871 Mon Sep 17 00:00:00 2001 From: Richard Frankel Date: Fri, 17 Nov 2023 02:44:26 -0600 Subject: [PATCH 11/12] Add a slug to AIP-122. --- aep/general/0122/aep.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/aep/general/0122/aep.yaml b/aep/general/0122/aep.yaml index 9c506aa3..341e073c 100644 --- a/aep/general/0122/aep.yaml +++ b/aep/general/0122/aep.yaml @@ -1,5 +1,6 @@ --- id: 122 +slug: resource-paths state: approved created: 2023-10-11 placement: From 7c2909655394cdd02c44ec8fdffd368acebec5fc Mon Sep 17 00:00:00 2001 From: Richard Frankel Date: Fri, 17 Nov 2023 15:47:39 -0500 Subject: [PATCH 12/12] Update aep/general/0122/aep.yaml Co-authored-by: Yusuke Tsutsumi --- aep/general/0122/aep.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aep/general/0122/aep.yaml b/aep/general/0122/aep.yaml index 341e073c..cf79b5d8 100644 --- a/aep/general/0122/aep.yaml +++ b/aep/general/0122/aep.yaml @@ -4,6 +4,6 @@ slug: resource-paths state: approved created: 2023-10-11 placement: - category: resource-design + category: resources order: 20 redirect_from: /resource-paths