Skip to content

Delete

In REST APIs, it is customary to make a DELETE request to a resource’s URI (for example, /v1/publishers/{publisher}/books/{book}) in order to delete that resource.

Resource-oriented design (AEP-121) honors this pattern through the Delete method. This method accepts the URI representing that resource and usually returns an empty response.

Guidance

APIs should generally provide a delete method for resources unless it is not valuable for users to do so.

The Delete method should succeed if and only if a resource was present and was successfully deleted. If the resource did not exist, the method should send a 404 Not found (NOT_FOUND) error.

If the API is operating on the Management Plane, the method should have strong consistency: the completion of a delete method must mean that the existence of the resource has reached a steady-state and reading resource state returns a consistent 404 Not found (NOT_FOUND) response.

Delete methods are specified using the following pattern:

  • The method’s name must begin with the word Delete. The remainder of the method name should be the singular form of the resource’s name.
  • The request schema name must exactly match the method name, with a Request suffix.
  • The response message should be an empty object.
    • If the delete method is long-running, the response schema must be an Operation which resolves to the correct response.
rpc DeleteBook(DeleteBookRequest) returns (google.protobuf.Empty) {
option (google.api.http) = {
delete: "/v1/{path=publishers/*/books/*}"
};
option (google.api.method_signature) = "path";
}
  • The response message should be google.protobuf.Empty.

    • If the delete RPC is long-running, the response message must be a aep.api.Operation which resolves to the correct response.
  • The request message field receiving the resource path should map to the URI path.

    • This field should be called path.
    • The path field should be the only variable in the URI path. All remaining parameters should map to URI query parameters.
  • There must not be a body key in the google.api.http annotation.

  • There should be exactly one google.api.method_signature annotation, with a value of "path". If an etag or force field are used, they may be included in the signature.

Requests

Delete methods implement a common request pattern:

  • The HTTP verb must be DELETE.
  • There must not be a request body.
  • If a delete request contains a body, the body must be ignored, and must not cause an error (this is required by RFC 9110)
  • The request must not require any fields in the query string. The request should not include optional fields in the query string unless described in another AEP.
message DeleteBookRequest {
// The path of the book to delete.
// Format: publishers/{publisher}/books/{book}
string path = 1 [
(google.api.field_behavior) = REQUIRED,
(google.api.resource_reference) = {
type: "library.example.com/Book"
}];
}
  • A path field must be included. It should be called path.

  • The comment for the field should document the resource pattern.

  • The request message must not contain any other required fields, and should not contain other optional fields except those described in this or another AEP.

Soft delete

Long-running delete

Some resources take longer to delete than is reasonable for a regular API request. In this situation, the API should use a long-running operation instead: AEP-151.

  • The response field of the response body must be an empty object to be consistent with the appropriate return type if the method was not long-running.
rpc DeleteBook(DeleteBookRequest) returns (aep.api.Operation) {
option (google.api.http) = {
delete: "/v1/{path=publishers/*/books/*}"
};
option (aep.api.operation_info) = {
response_type: "google.protobuf.Empty"
metadata_type: "OperationMetadata"
};
}
  • The response field of the response must be google.protobuf.Empty to be consistent with the appropriate return type if the method was not long-running.

  • Both the response_type and metadata_type fields must be specified (even if they are google.protobuf.Empty).

Cascading delete

Sometimes, it may be necessary for users to be able to delete a resource as well as all applicable child resources. However, since deletion is usually permanent, it is also important that users not do so accidentally, as reconstructing wiped-out child resources may be quite difficult.

If an API allows deletion of a resource that may have child resources, the API must provide a bool force field on the request, which the user sets to explicitly opt in to a cascading delete.

message DeletePublisherRequest {
// The path of the publisher to delete.
// Format: publishers/{publisher}
string path = 1 [
(google.api.field_behavior) = REQUIRED,
(google.api.resource_reference) = {
type: "library.example.com/Publisher"
}];
// If set to true, any books from this publisher will also be deleted.
// (Otherwise, the request will only work if the publisher has no books.)
bool force = 2;
}

The API must fail with a FAILED_PRECONDITION error if the force field is false (or unset) and child resources are present.

Errors

If the user does not have permission to access the resource, regardless of whether or not it exists, the service must error with 403 Forbidden (PERMISSION_DENIED). Permission must be checked prior to checking if the resource exists.

If the user does have proper permission, but the requested resource does not exist, the service must error with 404 Not found (NOT_FOUND).

Further reading

  • For soft delete and undelete, see AEP-164.
  • For bulk deleting large numbers of resources based on a filter, see AEP-165.

Changelog