Skip to content

Commit 32f2e1f

Browse files
Clean up AIP-136: Custom methods. (#103)
* Clean up AIP-136: Custom methods. This is in preparation for the barn raising event, and makes the AEP more consistent with more recently-adopted AEPs. Common guidance is also factored out of the IDL-specific tabs. I added one new bullet point of guidance while I was at it. I doubt this will be controversial, but calling it out for completeness. I actually think most of the changes from the Google AIP are pretty good in this case, so I have generally not modified them. * Update creation date * Update aep/general/0136/aep.md.j2 Co-authored-by: Yusuke Tsutsumi <yusuke@tsutsumi.io> * Update aep/general/0136/aep.md.j2 Co-authored-by: Yusuke Tsutsumi <yusuke@tsutsumi.io> * Address PR comments --------- Co-authored-by: Yusuke Tsutsumi <yusuke@tsutsumi.io>
1 parent f2aa796 commit 32f2e1f

3 files changed

Lines changed: 76 additions & 64 deletions

File tree

aep/general/0136/aep.md.j2

Lines changed: 67 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,76 +1,84 @@
1-
# Custom operations
1+
# Custom methods
22

3-
Services use custom operations to provide a means to express arbitrary actions
4-
that are difficult to model using only the standard operations. Custom
5-
operations are important because they provide a means for an API's vocabulary
6-
to adhere to user intent.
3+
Resource oriented design (AEP-121) uses custom methods to provide a means to
4+
express actions that are difficult to model using only the standard methods.
5+
Custom methods are important because they provide a means for an API's
6+
vocabulary to adhere to user intent.
77

88
## Guidance
99

10-
Custom operations **should** only be used for functionality that can not be
11-
easily expressed via standard operations; prefer standard operations if
12-
possible, due to their consistent semantics. (Of course, this only applies if
13-
the functionality in question actually conforms to the normal semantics; it is
14-
_not_ a good idea to contort things to endeavor to make the standard operations
15-
"sort of work".)
10+
Custom methods **should** only be used for functionality that can not be
11+
expressed via standard methods; prefer standard methods if possible, due to
12+
their consistent semantics. However, APIs **should not** contort things to
13+
endeavor to make the standard methods "sort of work".
1614

17-
While custom operations vary widely in how they are designed, many principles
15+
While custom methods vary widely in how they are designed, many principles
1816
apply consistently:
1917

18+
- The HTTP method for custom methods **should** be selected based on the
19+
semantics described by [RFC 7231 section 4.3] and [RFC 5789] for `PATCH`. In
20+
practice, the vast majority of custom methods **should** use `POST` or `GET`.
21+
- Custom methods that serve as an alternative to get or list methods (such as
22+
`Search`) **should** use `GET`, and require no request body. These methods
23+
**must** be idempotent and have no state changes or side effects (they
24+
should be safe as defined in [RFC 7231 section 4.2.1][]).
25+
- Custom methods **should not** use `PATCH` or `DELETE`.
26+
- The HTTP URI **must** use a `:` character followed by the custom verb
27+
(`:archive` in the above example), and the verb in the URI **must** match the
28+
verb in the name of the RPC.
29+
- If word separation is required, `camelCase` **must** be used.
30+
2031
{% tab proto %}
2132

2233
{% sample 'library.proto', 'rpc ArchiveBook' %}
2334

2435
- The name of the RPC **should** be a verb followed by a noun.
2536
- The name **must not** contain prepositions ("for", "with", etc.).
26-
- The HTTP method for custom operations **should** usually be `POST`, unless
27-
the custom method maps more strongly to another HTTP verb.
28-
- Custom operations that serve as an alternative to get or list operations
29-
(such as `Search`) **should** use `GET`. These operations **must** be
30-
idempotent and have no state changes or side effects (they should be safe
31-
as defined in [RFC 7231][]).
32-
- Custom operations **should not** use `PATCH` or `DELETE`.
33-
- The HTTP URI **must** use a `:` character followed by the custom verb
34-
(`:archive` in the above example), and the verb in the URI **must** match the
35-
verb in the name of the RPC.
36-
- If word separation is required, `camelCase` **must** be used.
3737
- The `body` clause in the `google.api.http` annotation **should** be `"*"`.
3838
- However, if using `GET` or `DELETE`, the `body` clause **must** be absent.
39-
- Custom operations **should** usually take a request message matching the RPC
40-
name, with a -`Request` suffix.
41-
- Custom operations **should** usually return a response message matching the
42-
RPC name, with a -`Response` suffix.
39+
- Custom methods **must** take a request message exactly matching the RPC name,
40+
with a `Request` suffix. For example, `ArchiveBookRequest`.
41+
- Custom methods **should** return a response message exactly matching the RPC
42+
name, with a `Response` suffix. For example, `ArchiveBookResponse`.
4343
- When operating on a specific resource, a custom method **may** return the
4444
resource itself.
4545

4646
{% tab oas %}
4747

4848
{% sample 'library.oas.yaml', '/publishers/{publisherId}/books/{bookId}:archive' %}
4949

50-
- The `operationId` **should** be a verb followed by a noun.
51-
- The `operationId` **must not** contain prepositions ("for", "with", etc.).
52-
- The HTTP method for custom operations **should** usually be `POST`, unless
53-
the custom method maps more strongly to another HTTP verb.
54-
- Custom operations that serve as an alternative to get or list operations
55-
(such as `Search`) **should** use `GET`, and require no request body. These
56-
operations **must** be idempotent and have no state changes or side effects
57-
(they should be safe as defined in [RFC 7231][]).
58-
- Custom operations **should not** use `PATCH` or `DELETE`.
59-
- The HTTP URI **must** use a `:` character followed by the custom verb
60-
(`:archive` in the above example), and the verb in the URI **must** match the
61-
verb in the `operationId`.
62-
- If word separation is required, `camelCase` **must** be used.
50+
- The name of the RPC **should** be a verb followed by a noun.
51+
- The name of the RPC **must not** contain prepositions ("for", "with",
52+
etc.).
6353

6454
{% endtabs %}
6555

6656
**Note:** The pattern above shows a custom method that operates on a specific
67-
resource. Custom operations can be associated with resources, collections, or
57+
resource. Custom methods can be associated with resources, collections, or
6858
services.
6959

70-
### Collection-based custom operations
60+
### Resource-based custom methods
61+
62+
Custom methods **must** operate on a resource if the API can be modeled as
63+
such:
64+
65+
{% tab proto %}
66+
67+
{% sample 'library.proto', 'rpc ArchiveBook' %}
68+
69+
- The parameter for the resource's path **must** be called `path`, and **must**
70+
be the only variable in the URI path.
71+
72+
{% tab oas %}
73+
74+
**Note:** OAS example not yet written.
75+
76+
{% endtabs %}
77+
78+
### Collection-based custom methods
7179

72-
While most custom operations operate on a single resource, some custom
73-
operations **may** operate on a collection instead:
80+
While most custom methods operate on a single resource, some custom methods
81+
**may** operate on a collection instead:
7482

7583
{% tab proto %}
7684

@@ -83,15 +91,14 @@ operations **may** operate on a collection instead:
8391
{% endtabs %}
8492

8593
- If the collection has a parent, the field name in the request message
86-
**should** be the target resource's singular noun (`publisher` in the above
87-
example). If word separators are necessary, `snake_case` **must** be used.
94+
**should** be `parent`.
8895
- The collection key (`books` in the above example) **must** be literal.
8996

90-
### Stateless operations
97+
### Stateless methods
9198

92-
Some custom operations are not attached to resources at all. These operations
93-
are generally _stateless_: they accept a request and return a response, and
94-
have no permanent effect on data within the API.
99+
Some custom methods are not attached to resources at all. These methods are
100+
generally _stateless_: they accept a request and return a response, and have no
101+
permanent effect on data within the API.
95102

96103
{% tab proto %}
97104

@@ -110,17 +117,21 @@ have no permanent effect on data within the API.
110117
- The URI **should** place both the verb and noun after the `:` separator
111118
(avoid a "faux collection key" in the URI in this case, as there is no
112119
collection). For example, `:translateText` is preferable to `text:translate`.
113-
- Stateless operations **must** use `POST` if they involve billing.
120+
- Stateless methods **must** use `POST` if they involve billing.
114121

115122
### Declarative-friendly resources
116123

117-
Declarative-friendly resources usually **should not** employ custom operations
118-
(except specific declarative-friendly custom operations discussed in other
119-
AEPs), because declarative-friendly tools are unable to automatically determine
120-
what to do with them.
124+
Declarative-friendly resources usually **should not** employ custom methods
125+
(except specific declarative-friendly custom methods discussed in other AEPs),
126+
because declarative-friendly tools are unable to automatically determine what
127+
to do with them.
121128

122129
An exception to this is for rarely-used, fundamentally imperative operations,
123130
such as a `Move`, `Rename`, or `Restart` operation, for which there would not
124131
be an expectation of declarative support.
125132

126-
[rfc 7231]: https://datatracker.ietf.org/doc/html/rfc7231#section-4.2.1
133+
<!-- prettier-ignore-start -->
134+
[rfc 5789]: https://datatracker.ietf.org/doc/html/rfc5789
135+
[rfc 7231 section 4.2.1]: https://datatracker.ietf.org/doc/html/rfc7231#section-4.2.1
136+
[rfc 7231 section 4.3]: https://datatracker.ietf.org/doc/html/rfc7231#section-4.3
137+
<!-- prettier-ignore-end -->

aep/general/0136/aep.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ id: 136
33
state: approved
44
slug: custom-methods
55
created: 2019-01-25
6+
updated: 2024-03-08
67
placement:
78
category: standard-methods
89
order: 100

aep/general/0136/library.proto

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,24 +23,24 @@ service Library {
2323
// Archives the given book.
2424
rpc ArchiveBook(ArchiveBookRequest) returns (ArchiveBookResponse) {
2525
option (google.api.http) = {
26-
post: "/v1/{name=publishers/*/books/*}:archive"
26+
post: "/v1/{path=publishers/*/books/*}:archive"
2727
body: "*"
2828
};
2929
}
3030

3131
// Sorts the books from this publisher.
3232
rpc SortBooks(SortBooksRequest) returns (SortBooksResponse) {
3333
option (google.api.http) = {
34-
post: "/v1/{publisher=publishers/*}/books:sort"
34+
post: "/v1/{parent=publishers/*}/books:sort"
3535
body: "*"
3636
};
3737
}
3838
}
3939

4040
// Request message to archive a book.
4141
message ArchiveBookRequest {
42-
// The name of the book to retrieve.
43-
string name = 1 [
42+
// The path of the book to retrieve.
43+
string path = 1 [
4444
(google.api.field_behavior) = REQUIRED,
4545
(google.api.resource_reference) = {
4646
type: "library.googleapis.com/Book"
@@ -59,8 +59,8 @@ message ArchiveBookResponse {
5959

6060
// Request message to sort a collection of books.
6161
message SortBooksRequest {
62-
// The name of the publisher to sort books for.
63-
string publisher = 1 [
62+
// The path of the publisher to sort books for.
63+
string parent = 1 [
6464
(google.api.field_behavior) = REQUIRED,
6565
(google.api.resource_reference) = {
6666
type: "library.googleapis.com/Publisher"
@@ -81,9 +81,9 @@ message Book {
8181
pattern: "publishers/{publisher}/books/{book}"
8282
};
8383

84-
// The name of the book.
84+
// The path of the book.
8585
// Format: publishers/{publisher}/books/{book}
86-
string name = 1;
86+
string path = 1;
8787

8888
// The ISBN (International Standard Book Number) for this book.
8989
string isbn = 2;

0 commit comments

Comments
 (0)