AIP-134
Standard methods: Update
In REST APIs, it is customary to make a PATCH
or PUT
request to a
resource's URI (for example, /v1/publishers/{publisher}/books/{book}
) in
order to update that resource.
Resource-oriented design (AIP-121) honors this pattern through the Update
method (which mirrors the REST PATCH
behavior). These RPCs accept the URI
representing that resource and return the resource.
Guidance
APIs should generally provide an update method for resources unless it is not valuable for users to do so. The purpose of the update method is to make changes to the resources without causing side effects.
Update methods are specified using the following pattern:
rpc UpdateBook(UpdateBookRequest) returns (Book) {
option (google.api.http) = {
patch: "/v1/{book.name=publishers/*/books/*}"
body: "book"
};
option (google.api.method_signature) = "book,update_mask";
}
- The RPC's name must begin with the word
Update
. The remainder of the RPC name should be the singular form of the resource's message name. - The request message must match the RPC name, with a
Request
suffix. - The response message must be the resource itself. (There is no
UpdateBookResponse
.)- The response should include the fully-populated resource, and must include any fields that were sent and included in the update mask unless they are input only (see AIP-203).
- If the update RPC is long-running, the response
message must be a
google.longrunning.Operation
which resolves to the resource itself.
- The method should support partial resource update, and the HTTP verb
should be
PATCH
.- If the method will only ever support full resource replacement, then the
HTTP verb may be
PUT
. However, this is strongly discouraged because it becomes a backwards-incompatible change to add fields to the resource.
- If the method will only ever support full resource replacement, then the
HTTP verb may be
- The resource's
name
field should map to the URI path.- The
{resource}.name
field should be the only variable in the URI path.
- The
- There must be a
body
key in thegoogle.api.http
annotation, and it must map to the resource field in the request message.- All remaining fields should map to URI query parameters.
- There should be exactly one
google.api.method_signature
annotation, with a value of"{resource},update_mask"
.
Note: Unlike the other four standard methods, the URI path here references
a nested field (book.name
) in the example. If the resource field has a word
separator, snake_case
is used.
Request message
Update methods implement a common request message pattern:
message UpdateBookRequest {
// The book to update.
//
// The book's `name` field is used to identify the book to update.
// Format: publishers/{publisher}/books/{book}
Book book = 1 [(google.api.field_behavior) = REQUIRED];
// The list of fields to update.
google.protobuf.FieldMask update_mask = 2;
}
- The request message must contain a field for the resource.
- The field must map to the
PATCH
body. - The field should be annotated as required.
- A
name
field must be included in the resource message. It should be calledname
. - The field must identify the resource type of the resource being updated.
- The field must map to the
- If partial resource update is supported, a field mask must be included.
It must be of type
google.protobuf.FieldMask
, and it should be calledupdate_mask
.- The fields used in the field mask correspond to the resource being updated (not the request message).
- The field may be required or optional. If it is required, it must include the corresponding annotation. If optional, the service must treat an omitted field mask as an implied field mask equivalent to all fields that are populated (have a non-empty value).
- Update masks must support a special value
*
, meaning full replacement (the equivalent ofPUT
).
- The request message must not contain any other required fields, and should not contain other optional fields except those described in this or another AIP.
Side effects
In general, update methods are intended to update the data within the resource. Update methods should not trigger other side effects. Instead, side effects should be triggered by custom methods.
In particular, this entails that state fields must not be directly writable in update methods.
PATCH and PUT
TL;DR: Google APIs generally use the PATCH
HTTP verb only, and do not
support PUT
requests.
We standardize on PATCH
because Google updates stable APIs in place with
backwards-compatible improvements. It is often necessary to add a new field to
an existing resource, but this becomes a breaking change when using PUT
.
To illustrate this, consider a PUT
request to a Book
resource:
PUT /v1/publishers/123/books/456
{"title": "Mary Poppins", "author": "P.L. Travers"}
Next consider that the resource is later augmented with a new field (here we
add rating
):
message Book {
string title = 1;
string author = 2;
// Subsequently added to v1 in place...
int32 rating = 3;
}
If a rating is set on a book and the existing PUT
request was executed, it
would wipe out the book's rating. In essence, a PUT
request unintentionally
wiped out data because the previous version did not know about it.
Long-running update
Some resources take longer to update a resource than is reasonable for a regular API request. In this situation, the API should use a long-running operation (AIP-151) instead:
rpc UpdateBook(UpdateBookRequest) returns (google.longrunning.Operation) {
option (google.api.http) = {
patch: "/v1/{book.name=publishers/*/books/*}"
};
option (google.longrunning.operation_info) = {
response_type: "Book"
metadata_type: "OperationMetadata"
};
}
- The response type must be set to the resource (what the return type would be if the RPC was not long-running).
- Both the
response_type
andmetadata_type
fields must be specified.
Note: Declarative-friendly resources (AIP-128) should use long-running update.
Create or update
If the service uses client-assigned resource names, Update
methods may
expose a bool allow_missing
field, which will cause the method to succeed in
the event that the user attempts to update a resource that is not present (and
will create the resource in the process):
message UpdateBookRequest {
// The book to update.
//
// The book's `name` field is used to identify the book to be updated.
// Format: publishers/{publisher}/books/{book}
Book book = 1 [(google.api.field_behavior) = REQUIRED];
// The list of fields to be updated.
google.protobuf.FieldMask update_mask = 2;
// If set to true, and the book is not found, a new book will be created.
// In this situation, `update_mask` is ignored.
bool allow_missing = 3;
}
More specifically, the allow_missing
flag triggers the following behavior:
- If the method call is on a resource that does not exist, the resource is
created. All fields are applied regardless of any provided field mask.
- However, if any required fields are missing or fields have invalid values,
an
INVALID_ARGUMENT
error is returned.
- However, if any required fields are missing or fields have invalid values,
an
- If the method call is on a resource that already exists, and all fields match, the existing resource is returned unchanged.
- If the method call is on a resource that already exists, only fields declared in the field mask are updated.
The user must have the update permissions to call Update
even with
allow_missing
set to true
. For customers that want to prevent users from
creating resources using the update method, IAM conditions should be used.
Etags
An API may sometimes need to allow users to send update requests which are
guaranteed to be made against the most current data (a common use case for this
is to detect and avoid race conditions). Resources which need to enable this do
so by including a string etag
field, which contains an opaque,
server-computed value representing the content of the resource.
In this situation, the resource should contain a string etag
field:
message Book {
// The resource name of the book.
// Format: publishers/{publisher}/books/{book}
string name = 1;
// The title of the book.
// Example: "Mary Poppins"
string title = 2;
// The author of the book.
// Example: "P.L. Travers"
string author = 3;
// The etag for this book.
// If this is provided on update, it must match the server's etag.
string etag = 4;
}
The etag
field may be either required or optional. If it is set,
then the request must succeed if and only if the provided etag matches the
server-computed value, and must fail with an ABORTED
error otherwise. The
update_mask
field in the request does not affect the behavior of the etag
field, as it is not a field being updated.
Expensive fields
APIs sometimes encounter situations where some fields on a resource are expensive or impossible to reliably return.
This can happen in a few situations:
- A resource may have some fields that are very expensive to compute, and that are generally not useful to the customer on update requests.
- A single resource sometimes represents an amalgamation of data from multiple underlying (and eventually consistent) data sources. In these situations, it is impossible to return authoritative information on the fields that were not changed.
In this situation, an API may return back only the fields that were updated, and omit the rest, and should document this behavior if they do so.
Errors
See errors, in particular when to use PERMISSION_DENIED and NOT_FOUND errors.
In addition, if the user does have proper permission, but the requested resource
does not exist, the service must error with NOT_FOUND
(HTTP 404) unless
allow_missing
is set to true
.
Changelog
- 2022-11-04: Aggregated error guidance to AIP-193.
- 2022-06-02: Changed suffix descriptions to eliminate superfluous "-".
- 2021-11-04: Changed the permission check if
allow_missing
is set. - 2021-07-08: Added error guidance for resource not found case.
- 2021-03-05: Changed the etag error from
FAILED_PRECONDITION
(which becomes HTTP 400) toABORTED
(409). - 2020-10-06: Added guidance for declarative-friendly resources.
- 2020-10-06: Added guidance for
allow_missing
. - 2020-08-14: Added error guidance for permission denied cases.
- 2020-06-08: Added guidance on returning the full resource.
- 2019-10-18: Added guidance on annotations.
- 2019-09-10: Added a link to the long-running operations AIP ([AIP-151][]).
- 2019-08-01: Changed the examples from "shelves" to "publishers", to present a better example of resource ownership.
- 2019-06-10: Added guidance for long-running update.
- 2019-05-29: Added an explicit prohibition on arbitrary fields in standard methods.