diff --git a/aip/general/0131/aip.md.j2 b/aip/general/0131/aip.md.j2 index 3fb804eb..f192573f 100644 --- a/aip/general/0131/aip.md.j2 +++ b/aip/general/0131/aip.md.j2 @@ -4,7 +4,7 @@ In REST APIs, it is customary to make a `GET` request to a resource's URI (for example, `/v1/publishers/{publisher}/books/{book}`) in order to retrieve that resource. -Our APIs honor this pattern by allowing `GET` requests to be sent to the +Services implement this pattern by allowing `GET` requests to be sent to the resource URI, which returns the resource itself. ## Guidance @@ -53,9 +53,9 @@ any additional wrapping: ### Errors If the user does not have sufficient permission to know that the resource -exists, the service **should** reply with an HTTP 404 error, regardless of -whether or not the resource exists. Permission **must** be checked prior to -checking if the resource exists. +exists, the service **should** reply with an HTTP 403 error, regardless of +whether or not the resource exists, as described in AIP-211. Permission +**must** be checked prior to checking if the resource exists. If the user has sufficient permission to know that the resource exists, but is unable to access it, the service **should** reply with an HTTP 403 error. diff --git a/aip/general/0135/aip.md.j2 b/aip/general/0135/aip.md.j2 new file mode 100644 index 00000000..ce436f21 --- /dev/null +++ b/aip/general/0135/aip.md.j2 @@ -0,0 +1,213 @@ +# DELETE for individual resources + +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. + +Services implement this pattern by allowing `DELETE` requests to be sent to the +resource URI, which deletes the resource. + +## Guidance + +APIs **should** generally provide a `DELETE` method for resources unless it is +not valuable for users to do so. When the `DELETE` method is used on a URI +ending in a resource ID or resource ID alias, the resource should be deleted, +and the result should be a `204 No Content` empty response. + +### Requests + +Single-resource `DELETE` operations **must** be made by sending a `DELETE` +request to the resource's URI: + +```http +DELETE /v1/publishers/{publisher}/books/{book} HTTP/2 +Host: library.googleapis.com +Accept: application/json +``` + +- The HTTP method **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. +- 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 AIP. +- Single-resource `DELETE` operations **must** return `204 No Content` with no + response body. + - Exception: If the resource is soft deleted (AIP-164), in which case the + operation **must** return `200 OK` and the resource itself, without any + additional wrapping. + +{% tab proto %} + +{% sample 'delete.proto', 'rpc DeleteBook' %} + +- The RPC's name **must** begin with the word `Delete`. 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 **should** be `google.protobuf.Empty`. + - If the resource is [soft deleted](#soft-delete), the response message + **should** be the resource itself. + - If the delete RPC is [long-running](#long-running-delete), the response + message **must** be a `google.longrunning.Operation` which resolves to the + correct response. +- The request message field receiving the resource name **should** map to the + URI path. + - This field **should** be called `name`. + - The `name` 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 `"name"`. If an etag or force field are used, they **may** be + included in the signature. + +`Delete` methods have consistent request messages: + +{% sample 'delete.proto', 'message DeleteBookRequest' %} + +- A `name` field **must** be included. It **should** be called `name`. + - The field **should** be [annotated as required][aip-203]. + - The field **should** identify the [resource type][aip-123] that it + references. +- 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 AIP. + +{% tab oas %} + +{% sample 'delete.oas.yaml', 'paths' %} + +- The `operationId` **must** begin with the word `delete`. The remainder of the + `operationId` **should** be the singular form of the resource type's name. +- The URI **should** contain a variable for each individual ID in the resource + hierarchy. + - The path parameter for all resource IDs **must** be in the form + `{resourceName}Id` (such as `bookId`), and path parameters representing the + ID of the parent resources **must** end with `Id`. + +{% endtabs %} + +### Errors + +If the user does not have sufficient permission to know that the resource +exists, the service **should** reply with an HTTP 403 error, regardless of +whether or not the resource exists, as described in AIP-211. Permission +**must** be checked prior to checking if the resource exists. + +If the user has sufficient permission to know that the resource exists, but is +unable to access it, the service **should** error with `403 Forbidden`. + +If the user does have proper permission, but the requested resource does not +exist, the service **must** error with `404 Not Found` unless `allow_missing` +is set to `true`. + +### Soft delete + +**Note:** This material was moved into its own document to provide a more +comprehensive treatment: AIP-164. + +### Long-running delete + +Some resources take longer to delete a resource than is reasonable for a +regular API request. In this situation, the operation **should** be defined as +a [long-running request][aip-151] instead: + +{% tab proto %} + +{% sample 'lro_delete.proto', 'rpc DeleteBook' %} + +- The response type **must** be set to the appropriate return type if the RPC + was not long-running: `google.protobuf.Empty` for most Delete RPCs, or the + resource itself for soft delete (AIP-164). +- Both the `response_type` and `metadata_type` fields **must** be specified + (even if they are `google.protobuf.Empty`). + +{% tab oas %} + +{% sample 'lro_delete.oas.yaml', 'paths' %} + +{% endtabs %} + +**Note:** Declarative-friendly resources (AIP-128) **should** use long-running +delete. + +### 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 +**should** provide a `bool force` field on the request, which the user sets to +explicitly opt in to a cascading delete. + +{% tab proto %} + +{% sample 'cascading_delete.proto', 'message DeletePublisherRequest' %} + +{% tab oas %} + +{% sample 'cascading_delete.oas.yaml', 'paths' %} + +{% endtabs %} + +The API **must** error with `412 Precondition Failed` if the `force` field is +`false` (or unset) and child resources are present. + +### Protected delete + +Sometimes, it may be necessary for users to ensure that no changes have been +made to a resource that is being deleted. If a resource provides an +[etag][aip-154], the delete request **may** accept the etag (as either required +or optional): + +{% tab proto %} + +{% sample 'protected_delete.proto', 'message DeleteBookRequest' %} + +{% tab oas %} + +{% sample 'protected_delete.oas.yaml', 'paths' %} + +{% endtabs %} + +If the etag is provided and does not match the server-computed etag, the +request **must** error with `412 Precondition Failed`. + +**Note:** Declarative-friendly resources (AIP-128) **must** provide +[etags][aip-154] for Delete requests. + +### Delete if existing + +If the service uses client-assigned resource names, `Delete` methods **may** +expose a `bool allow_missing` field, which will cause the method to succeed in +the event that the user attempts to delete a resource that is not present (in +which case the request is a no-op): + +{% tab proto %} + +{% sample 'delete_if_existing.proto', 'message DeleteBookRequest' %} + +{% tab oas %} + +{% sample 'delete_if_existing.oas.yaml', 'paths' %} + +{% endtabs %} + +More specifically, the `allow_missing` flag triggers the following behavior: + +- If the method call is on a resource that does not exist, the request is a + no-op. + - The `etag` field is ignored. +- If the method call is on a resource that already exists, the resource is + deleted (subject to other checks). + +**Note:** Declarative-friendly resources (AIP-128) **should** expose the +`bool allow_missing` field. + +## Further reading + +- For soft delete and undelete, see AIP-164. +- For bulk deleting large numbers of resources based on a filter, see AIP-165. diff --git a/aip/general/0135/aip.yaml b/aip/general/0135/aip.yaml new file mode 100644 index 00000000..b93141c5 --- /dev/null +++ b/aip/general/0135/aip.yaml @@ -0,0 +1,7 @@ +--- +id: 135 +state: approved +created: 2019-01-24 +placement: + category: operations + order: 50 diff --git a/aip/general/0135/cascading_delete.oas.yaml b/aip/general/0135/cascading_delete.oas.yaml new file mode 100644 index 00000000..b1348f58 --- /dev/null +++ b/aip/general/0135/cascading_delete.oas.yaml @@ -0,0 +1,65 @@ +--- +openapi: 3.0.3 +info: + title: Library + version: 1.0.0 +paths: + /publishers/{publisherId}/books/{bookId}: + parameters: + - $ref: "#/components/parameters/PublisherId" + - $ref: "#/components/parameters/BookId" + delete: + operationId: deleteBook + description: Delete a single book. + parameters: + - in: query + name: force + schema: + type: boolean + description: | + If set to true, any books from this publisher will also be deleted. + (Otherwise, the request fails unless the publisher has no books.) + responses: + '204': + description: Book was deleted +components: + parameters: + PublisherId: + name: publisherId + in: path + description: The id of the book publisher. + required: true + schema: + type: string + BookId: + name: bookId + in: path + description: The id of the book. + required: true + schema: + type: string + schemas: + Book: + description: A representation of a single book. + properties: + name: + type: string + description: | + The name of the book. + Format: publishers/{publisher}/books/{book} + isbn: + type: string + description: | + The ISBN (International Standard Book Number) for this book. + title: + type: string + description: The title of the book. + authors: + type: array + items: + type: string + description: The author or authors of the book. + rating: + type: number + format: float32 + description: The rating assigned to the book. diff --git a/aip/general/0135/cascading_delete.proto b/aip/general/0135/cascading_delete.proto new file mode 100644 index 00000000..6c5cf079 --- /dev/null +++ b/aip/general/0135/cascading_delete.proto @@ -0,0 +1,46 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +import "google/api/annotations.proto"; +import "google/api/client.proto"; +import "google/api/field_behavior.proto"; +import "google/api/resource.proto"; +import "google/protobuf/empty.proto"; + +service Library { + // Delete a single book. + rpc DeletePublisher(DeletePublisherRequest) returns (google.protobuf.Empty) { + option (google.api.http) = { + delete: "/v1/{name=publishers/*}" + }; + option (google.api.method_signature) = "name"; + } +} + +// Request message to delete a publisher. +message DeletePublisherRequest { + // The name of the publisher to delete. + // Format: publishers/{publisher} + string name = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { + type: "library.googleapis.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; +} diff --git a/aip/general/0135/delete.oas.yaml b/aip/general/0135/delete.oas.yaml new file mode 100644 index 00000000..26b809fe --- /dev/null +++ b/aip/general/0135/delete.oas.yaml @@ -0,0 +1,57 @@ +--- +openapi: 3.0.3 +info: + title: Library + version: 1.0.0 +paths: + /publishers/{publisherId}/books/{bookId}: + parameters: + - $ref: "#/components/parameters/PublisherId" + - $ref: "#/components/parameters/BookId" + delete: + operationId: deleteBook + description: Delete a single book. + responses: + '204': + description: Book was deleted +components: + parameters: + PublisherId: + name: publisherId + in: path + description: The id of the book publisher. + required: true + schema: + type: string + BookId: + name: bookId + in: path + description: The id of the book. + required: true + schema: + type: string + schemas: + Book: + description: A representation of a single book. + properties: + name: + type: string + description: | + The name of the book. + Format: publishers/{publisher}/books/{book} + isbn: + type: string + description: | + The ISBN (International Standard Book Number) for this book. + title: + type: string + description: The title of the book. + authors: + type: array + items: + type: string + description: The author or authors of the book. + rating: + type: number + format: float32 + description: The rating assigned to the book. diff --git a/aip/general/0135/delete.proto b/aip/general/0135/delete.proto new file mode 100644 index 00000000..529215a9 --- /dev/null +++ b/aip/general/0135/delete.proto @@ -0,0 +1,65 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +import "google/api/annotations.proto"; +import "google/api/client.proto"; +import "google/api/field_behavior.proto"; +import "google/api/resource.proto"; +import "google/protobuf/empty.proto"; + +service Library { + // Delete a single book. + rpc DeleteBook(DeleteBookRequest) returns (google.protobuf.Empty) { + option (google.api.http) = { + delete: "/v1/{name=publishers/*/books/*}" + }; + option (google.api.method_signature) = "name"; + } +} + +// Request message to delete a single book. +message DeleteBookRequest { + // The name of the book to delete. + string name = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { + type: "library.googleapis.com/Book" + }]; +} + +// A representation of a single book. +message Book { + option (google.api.resource) = { + type: "library.googleapis.com/Book" + pattern: "publishers/{publisher}/books/{book}" + }; + + // The name of the book. + // Format: publishers/{publisher}/books/{book} + string name = 1; + + // The ISBN (International Standard Book Number) for this book. + string isbn = 2; + + // The title of the book. + string title = 3; + + // The author or authors of the book. + repeated string authors = 4; + + // The rating assigned to the book. + float rating = 5; +} diff --git a/aip/general/0135/delete_if_existing.oas.yaml b/aip/general/0135/delete_if_existing.oas.yaml new file mode 100644 index 00000000..43765103 --- /dev/null +++ b/aip/general/0135/delete_if_existing.oas.yaml @@ -0,0 +1,65 @@ +--- +openapi: 3.0.3 +info: + title: Library + version: 1.0.0 +paths: + /publishers/{publisherId}/books/{bookId}: + parameters: + - $ref: "#/components/parameters/PublisherId" + - $ref: "#/components/parameters/BookId" + delete: + operationId: deleteBook + description: Delete a single book. + parameters: + - in: query + name: allow_missing + schema: + type: boolean + description: | + If set to true, and the book is not found, the request will succeed + but no action will be taken on the server + responses: + '204': + description: Book was deleted +components: + parameters: + PublisherId: + name: publisherId + in: path + description: The id of the book publisher. + required: true + schema: + type: string + BookId: + name: bookId + in: path + description: The id of the book. + required: true + schema: + type: string + schemas: + Book: + description: A representation of a single book. + properties: + name: + type: string + description: | + The name of the book. + Format: publishers/{publisher}/books/{book} + isbn: + type: string + description: | + The ISBN (International Standard Book Number) for this book. + title: + type: string + description: The title of the book. + authors: + type: array + items: + type: string + description: The author or authors of the book. + rating: + type: number + format: float32 + description: The rating assigned to the book. diff --git a/aip/general/0135/delete_if_existing.proto b/aip/general/0135/delete_if_existing.proto new file mode 100644 index 00000000..2900d09f --- /dev/null +++ b/aip/general/0135/delete_if_existing.proto @@ -0,0 +1,69 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +import "google/api/annotations.proto"; +import "google/api/client.proto"; +import "google/api/field_behavior.proto"; +import "google/api/resource.proto"; +import "google/protobuf/empty.proto"; + +service Library { + // Delete a single book. + rpc DeleteBook(DeleteBookRequest) returns (google.protobuf.Empty) { + option (google.api.http) = { + delete: "/v1/{name=publishers/*/books/*}" + }; + option (google.api.method_signature) = "name"; + } +} + +// Request message to delete a single book. +message DeleteBookRequest { + // The name of the book to delete. + string name = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { + type: "library.googleapis.com/Book" + }]; + + // If set to true, and the book is not found, the request will succeed + // but no action will be taken on the server + bool allow_missing = 2; +} + +// A representation of a single book. +message Book { + option (google.api.resource) = { + type: "library.googleapis.com/Book" + pattern: "publishers/{publisher}/books/{book}" + }; + + // The name of the book. + // Format: publishers/{publisher}/books/{book} + string name = 1; + + // The ISBN (International Standard Book Number) for this book. + string isbn = 2; + + // The title of the book. + string title = 3; + + // The author or authors of the book. + repeated string authors = 4; + + // The rating assigned to the book. + float rating = 5; +} diff --git a/aip/general/0135/lro_delete.oas.yaml b/aip/general/0135/lro_delete.oas.yaml new file mode 100644 index 00000000..15c89412 --- /dev/null +++ b/aip/general/0135/lro_delete.oas.yaml @@ -0,0 +1,107 @@ +--- +openapi: 3.0.3 +info: + title: Library + version: 1.0.0 +paths: + /publishers/{publisherId}/books/{bookId}: + parameters: + - $ref: "#/components/parameters/PublisherId" + - $ref: "#/components/parameters/BookId" + delete: + operationId: deleteBook + description: Delete a single book. + responses: + '202': + description: Accepted + content: + application/json: + schema: + $ref: '#/components/schemas/DeleteBookStatus' +components: + parameters: + PublisherId: + name: publisherId + in: path + description: The id of the book publisher. + required: true + schema: + type: string + BookId: + name: bookId + in: path + description: The id of the book. + required: true + schema: + type: string + schemas: + Book: + description: A representation of a single book. + properties: + name: + type: string + description: | + The name of the book. + Format: publishers/{publisher}/books/{book} + isbn: + type: string + description: | + The ISBN (International Standard Book Number) for this book. + title: + type: string + description: The title of the book. + authors: + type: array + items: + type: string + description: The author or authors of the book. + rating: + type: number + format: float32 + description: The rating assigned to the book. + DeleteBookStatus: + description: The status of the deleteBook operation. + allOf: + - $ref: '#/components/schemas/StatusMonitor' + - type: object + properties: + response: + type: object + description: Empty object. + metadata: + type: object + properties: + startTime: + type: string + format: date-time + description: The time the operation started. + progressPercent: + type: integer + format: int32 + description: The current progress, expressed as an integer. + state: + type: string + description: The current state of the operation. + enum: + - STATE_UNSPECIFIED + - RUNNING + - CANCELLING + - CANCELLED + - FAILED + StatusMonitor: + description: The status of a long running operation. + type: object + properties: + name: + type: string + description: The server-assigned name, which is only unique within the same service that originally returns it. + done: + type: boolean + description: >- + If the value is false, it means the operation is still in progress. If true, the operation is completed, + and either response or error is available. + error: + $ref: '#/components/schemas/Error' + required: + - name + - done \ No newline at end of file diff --git a/aip/general/0135/lro_delete.proto b/aip/general/0135/lro_delete.proto new file mode 100644 index 00000000..a1c3924d --- /dev/null +++ b/aip/general/0135/lro_delete.proto @@ -0,0 +1,69 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +import "google/api/annotations.proto"; +import "google/api/client.proto"; +import "google/api/field_behavior.proto"; +import "google/api/resource.proto"; +import "google/longrunning/operations.proto"; + +service Library { + // Delete a single book. + rpc DeleteBook(DeleteBookRequest) returns (google.longrunning.Operation) { + option (google.api.http) = { + delete: "/v1/{name=publishers/*/books/*}" + }; + option (google.longrunning.operation_info) = { + response_type: "google.protobuf.Empty" + metadata_type: "OperationMetadata" + }; + option (google.api.method_signature) = "name"; + } +} + +// Request message to delete a single book. +message DeleteBookRequest { + // The name of the book to delete. + string name = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { + type: "library.googleapis.com/Book" + }]; +} + +// A representation of a single book. +message Book { + option (google.api.resource) = { + type: "library.googleapis.com/Book" + pattern: "publishers/{publisher}/books/{book}" + }; + + // The name of the book. + // Format: publishers/{publisher}/books/{book} + string name = 1; + + // The ISBN (International Standard Book Number) for this book. + string isbn = 2; + + // The title of the book. + string title = 3; + + // The author or authors of the book. + repeated string authors = 4; + + // The rating assigned to the book. + float rating = 5; +} diff --git a/aip/general/0135/protected_delete.oas.yaml b/aip/general/0135/protected_delete.oas.yaml new file mode 100644 index 00000000..c486d4ed --- /dev/null +++ b/aip/general/0135/protected_delete.oas.yaml @@ -0,0 +1,65 @@ +--- +openapi: 3.0.3 +info: + title: Library + version: 1.0.0 +paths: + /publishers/{publisherId}/books/{bookId}: + parameters: + - $ref: "#/components/parameters/PublisherId" + - $ref: "#/components/parameters/BookId" + delete: + operationId: deleteBook + description: Delete a single book. + parameters: + - in: header + name: If-Match + schema: + type: string + description: | + The etag of the book. + If this is provided, it must match the server's etag. + responses: + '204': + description: Book was deleted +components: + parameters: + PublisherId: + name: publisherId + in: path + description: The id of the book publisher. + required: true + schema: + type: string + BookId: + name: bookId + in: path + description: The id of the book. + required: true + schema: + type: string + schemas: + Book: + description: A representation of a single book. + properties: + name: + type: string + description: | + The name of the book. + Format: publishers/{publisher}/books/{book} + isbn: + type: string + description: | + The ISBN (International Standard Book Number) for this book. + title: + type: string + description: The title of the book. + authors: + type: array + items: + type: string + description: The author or authors of the book. + rating: + type: number + format: float32 + description: The rating assigned to the book. diff --git a/aip/general/0135/protected_delete.proto b/aip/general/0135/protected_delete.proto new file mode 100644 index 00000000..397901aa --- /dev/null +++ b/aip/general/0135/protected_delete.proto @@ -0,0 +1,69 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +import "google/api/annotations.proto"; +import "google/api/client.proto"; +import "google/api/field_behavior.proto"; +import "google/api/resource.proto"; +import "google/protobuf/empty.proto"; + +service Library { + // Delete a single book. + rpc DeleteBook(DeleteBookRequest) returns (google.protobuf.Empty) { + option (google.api.http) = { + delete: "/v1/{name=publishers/*/books/*}" + }; + option (google.api.method_signature) = "name"; + } +} + +// Request message to delete a single book. +message DeleteBookRequest { + // The name of the book to delete. + string name = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { + type: "library.googleapis.com/Book" + }]; + + // Optional. The etag of the book. + // If this is provided, it must match the server's etag. + string etag = 2; +} + +// A representation of a single book. +message Book { + option (google.api.resource) = { + type: "library.googleapis.com/Book" + pattern: "publishers/{publisher}/books/{book}" + }; + + // The name of the book. + // Format: publishers/{publisher}/books/{book} + string name = 1; + + // The ISBN (International Standard Book Number) for this book. + string isbn = 2; + + // The title of the book. + string title = 3; + + // The author or authors of the book. + repeated string authors = 4; + + // The rating assigned to the book. + float rating = 5; +}