AIP-136

Custom methods

Resource-oriented design uses custom methods to provide a means to express arbitrary actions that are difficult to model using only the standard methods. Custom methods are important because they provide a means for an API’s vocabulary to adhere to user intent.

Guidance

Custom methods should only be used for functionality that can not be easily expressed via standard methods; prefer standard methods if possible, due to their consistent semantics. (Of course, this only applies if the functionality in question actually conforms to the normal semantics; it is not a good idea to contort things to endeavor to make the standard methods “sort of work”.)

While custom methods vary widely in how they are designed, many principles apply consistently:

// Archives the given book.
rpc ArchiveBook(ArchiveBookRequest) returns (ArchiveBookResponse) {
  option (google.api.http) = {
    post: "/v1/{name=publishers/*/books/*}:archive"
    body: "*"
  };
}

Note: The pattern above shows a custom method that operates on a specific resource. Custom methods can be associated with resources, collections, or services. The bullets below apply in all three cases.

  • The name of the method should be a verb followed by a noun.
    • The name must not contain prepositions (“for”, “with”, etc.).
  • The HTTP method for custom methods should usually be POST, unless the custom method maps more strongly to another HTTP verb.
    • Custom methods that serve as an alternative to get or list methods (such as Search) should use GET. These methods must be idempotent and have no side effects.
    • Custom methods should not use PATCH or DELETE.
  • The HTTP URI must use a : character followed by the custom verb (:archive in the above example), and the verb in the URI must match the verb in the name of the RPC.
    • If word separation is required, camelCase must be used.
  • The body clause in the google.api.http annotation should be "*".
    • However, if using GET or DELETE, the body clause must be absent.
  • Custom methods should usually take a request message matching the RPC name, with a -Request suffix.
  • Custom methods should usually return a response message matching the RPC name, with a -Response suffix.
    • When operating on a specific resource, a custom method may return the resource itself.

Collection-based custom methods

While most custom methods operate on a single resource, some resources may operate on a collection instead:

// Sorts the books from this publisher.
rpc SortBooks(SortBooksRequest) returns (SortBooksResponse) {
  option (google.api.http) = {
    post: "/v1/{publisher=publishers/*}/books:sort"
    body: "*"
  };
}
  • If the collection has a parent, the field name in the request message should be the target resource’s singular noun (publisher in the above example). If word separators are necessary, snake_case must be used.
  • The collection key (books in the above example) must be literal.

Stateless methods

Some custom methods are not attached to resources at all. These methods are generally stateless: they accept a request and return a response, and have no permanent effect on data within the API.

// Translates the provided text from one language to another.
rpc TranslateText(TranslateTextRequest) returns (TranslateTextResponse) {
  option (google.api.http) = {
    post: "/v1/{project=projects/*}:translateText"
    body: "*"
  };
}
  • If the method runs in a particular scope (such as a project, as in the above example), the field name in the request message should be the name of the scope resource. If word separators are necessary, snake_case must be used.
  • The URI should place both the verb and noun after the : separator (avoid a “faux collection key” in the URI in this case, as there is no collection). For example, :translateText is preferable to text:translate.
  • Stateless methods must use POST if they involve billing.

Changelog

  • 2019-08-01: Changed the examples from “shelves” to “publishers”, to present a better example of resource ownership.