@@ -98,6 +98,66 @@ rpc UndeleteBook(UndeleteBookRequest) returns (google.longrunning.Operation) {
9898 be if the RPC was not long-running).
9999- Both the ` response_type ` and ` metadata_type ` fields ** must** be specified.
100100
101+ ### Expunge
102+
103+ Resources that support soft delete ** may** provide an ` Expunge ` custom method to
104+ allow users to trigger immediate permanent deletion of a ready or soft-deleted
105+ resource. This method can operate on resources that are currently in a ready or
106+ soft-deleted state (e.g., ` delete_time ` is set).
107+
108+ ``` proto
109+ // Permanently deletes a soft-deleted Book.
110+ rpc ExpungeBook(ExpungeBookRequest) returns (google.protobuf.Empty) {
111+ option (google.api.http) = {
112+ post: "/v1/{name=publishers/*/books/*}:expunge"
113+ body: "*"
114+ };
115+ option (google.api.method_signature) = "name";
116+ }
117+ ```
118+
119+ - The URI must use a custom method with the : expunge suffix.
120+ - The HTTP verb must be POST and the body clause must be "* ".
121+ - The response message must be ` google.protobuf.Empty ` or a ` google.longrunning.Operation ` .
122+
123+ ### Long-running expunge
124+
125+ If the expunge process takes significant time, the method ** may** be a
126+ ` google.longrunning.Operation ` (AIP-151) instead:
127+
128+ ``` proto
129+ // Permanently deletes a soft-deleted Book.
130+ rpc ExpungeBook(ExpungeBookRequest) returns (google.longrunning.Operation) {
131+ option (google.api.http) = {
132+ post: "/v1/{name=publishers/*/books/*}:expunge"
133+ body: "*"
134+ };
135+ option (google.longrunning.operation_info) = {
136+ response_type: "google.protobuf.Empty"
137+ metadata_type: "OperationMetadata"
138+ };
139+ option (google.api.method_signature) = "name";
140+ }
141+ ```
142+
143+ ### Expunge request message
144+
145+ Expunge methods implement a common request message pattern:
146+
147+ ``` proto
148+ message ExpungeBookRequest {
149+ // The name of the soft-deleted book to expunge.
150+ // Format: publishers/{publisher}/books/{book}
151+ string name = 1 [
152+ (google.api.field_behavior) = REQUIRED,
153+ (google.api.resource_reference).type = "library.googleapis.com/Book"
154+ ];
155+ }
156+ ```
157+
158+ - The request message ** must** refer to the resource to be expunged by name.
159+ - There ** should not** be any other request fields.
160+
101161### List and Get
102162
103163Soft-deleted resources ** should not** be returned in ` List ` (AIP-132) responses
@@ -139,6 +199,16 @@ If the user calling `Undelete` has proper permission, but the requested
139199resource is not deleted, the service ** must** respond with ` ALREADY_EXISTS `
140200(HTTP 409).
141201
202+ If the user calling ` Expunge ` requests a resource that does not exist (was never
203+ created or already expunged), the method ** must** return ` NOT_FOUND ` (HTTP 404).
204+
205+ If the resource exists but is not in a ready or soft-deleted state, the method
206+ ** must** return ` FAILED_PRECONDITION ` (HTTP 400).
207+
208+ Standard permission errors (` PERMISSION_DENIED ` ) apply. Services ** must** require
209+ an explicit expunge permission that is separate from standard delete permissions
210+ (e.g., ` <service>.<resource>.expunge ` ).
211+
142212## Further reading
143213
144214- For the ` Delete ` standard method, see AIP-135.
@@ -148,6 +218,7 @@ resource is not deleted, the service **must** respond with `ALREADY_EXISTS`
148218
149219## Changelog
150220
221+ - ** 2026-04-28** : Added guidance for the ` Expunge ` custom method.
151222- ** 2024-09-24** : Included missing requirement for ` delete_time ` .
152223- ** 2023-07-13** : Renamed overloaded ` expire_time ` to ` purge_time ` .
153224- ** 2021-07-12** : Added error behavior when soft deleting a deleted resource.
0 commit comments