From 0f4deac14a767f8095595bb26f2e326d0c6b4633 Mon Sep 17 00:00:00 2001 From: Yusuke Tsutsumi Date: Fri, 13 Sep 2024 20:34:50 -0700 Subject: [PATCH] fix(methods): remove management plane, require strong consistency The introduction of the concept of management plane and data plane and it's subjective definition in the AEPs was leading to ambiguous guidance. Removing the mention of those concepts until a clearer criteria can be established. This change requires that a decision must be made for strong consistency. As operations that are not strongly consistent can result in manual per-resource patches for declarative clients, require strong consistency for all standard methods. --- aep/general/0121/aep.md.j2 | 20 ++++++++-------- aep/general/0133/aep.md.j2 | 22 +++++++----------- aep/general/0134/aep.md.j2 | 47 ++++++++++++++++++++++++++++++++++++-- aep/general/0135/aep.md.j2 | 9 ++++---- aep/general/0154/aep.md.j2 | 3 ++- 5 files changed, 70 insertions(+), 31 deletions(-) diff --git a/aep/general/0121/aep.md.j2 b/aep/general/0121/aep.md.j2 index 47d2fc57..bd2d6308 100644 --- a/aep/general/0121/aep.md.j2 +++ b/aep/general/0121/aep.md.j2 @@ -83,16 +83,19 @@ patterns, such as database transactions, import and export, or data analysis. ### Strong Consistency -For methods that operate on the [management plane][], the completion of those -operations (either successful or with an error, -[long-running][long-running-requests] or synchronous) **must** mean that the -state of the resource's existence and all user-settable values have reached a -steady-state. +An operation is strongly consistent if the completion of that operation (either +successful or with an error, [long-running][long-running-requests] or +synchronous) **must** mean that the state of the resource's existence and all +user-settable values have reached a steady-state. -[Output only][output only] values unrelated to the resource [state][] -**should** also have reached a steady-state. +[Output only][output only] fields unrelated to the resource [state][] +**should** also have reached a steady-state. Exceptional cases include: -Examples include: +- An output-only field that takes so long to reach a steady-state that it would + negatively impact the user experience of the request (e.g. an hour-long instantiation + of a VM cluster). + +Examples of strong consistency include: - Following a successful create that is is latest mutation on a resource, a get request for a resource **must** return the resource. @@ -141,7 +144,6 @@ turn do not increase resource management complexity. [get]: ./0131.md [list]: ./0132.md [long-running-requests]: ./0151.md -[management plane]: ./0111.md#management-plane [output only]: ./0203.md#output-only [rest]: https://en.wikipedia.org/wiki/Representational_state_transfer [resource references]: ./0122.md#fields-representing-another-resource diff --git a/aep/general/0133/aep.md.j2 b/aep/general/0133/aep.md.j2 index f3c7020a..726b1172 100644 --- a/aep/general/0133/aep.md.j2 +++ b/aep/general/0133/aep.md.j2 @@ -57,10 +57,7 @@ rpc CreateBook(CreateBookRequest) returns (Book) { - There **should** be exactly one `google.api.method_signature` annotation, with a value of `"parent,{resource},id"`, or "`"parent,{resource}"` if the resource ID is not required. -- If the API is operating on the [management plane][], the operation should have - [strong consistency][]: the completion of a create operation **must** mean - that all user-settable values and the existence of the resource have reached a - steady-state and reading resource state returns a consistent response. +- The operation **must** have [strong consistency][]. {% tab oas %} @@ -72,8 +69,7 @@ rpc CreateBook(CreateBookRequest) returns (Book) { Create methods implement a common request message pattern: -- An `id` field **must** be included for management plane resources, and - **should** be included for data plane resources. +- An `id` field **should** be supported. - The resource field **must** be included and **must** map to the POST body. - The request message **must not** contain any other required fields and **should not** contain other optional fields except those described in this @@ -148,16 +144,15 @@ rpc CreateBook(CreateBookRequest) returns (aep.api.Operation) { ### User-specified IDs -An API **must** allow a user to specify the ID component of a resource (the -last segment of the resource path) on creation if the API is operating on the -[management plane][]. +An API **should** allow a user to specify the ID component of a resource: not +doing so introduces a non-idempotent request in the API, as sending the same +payload results in creating a new resource each time. -On the [data plane][], an API **should** allow a user to specify the ID. Exceptional cases should have the following behavior: -- The data plane resource allows identical records without a need to - disambiguate between the two (e.g. rows in a table with no primary key). -- The data plane resource will not be exposed in [Declarative clients][]. +- The resource allows identical records without a need to disambiguate between + the two (e.g. rows in a table with no primary key). +- The resource will not be exposed in [Declarative clients][]. An API **may** allow the `id` field to be optional, and give the resource a system-generated ID if one is not specified. @@ -233,7 +228,6 @@ path and use it in references from other resources. [aep-203]: ./0203.md [aep-210]: ./0210.md [data plane]: ./0111.md#data-plane -[management plane]: ./0111.md#management-plane [errors]: ./0193.md [field_behavior]: ./203.md [Declarative clients]: ./0003.md#declarative-clients diff --git a/aep/general/0134/aep.md.j2 b/aep/general/0134/aep.md.j2 index 628be0dc..327ce791 100644 --- a/aep/general/0134/aep.md.j2 +++ b/aep/general/0134/aep.md.j2 @@ -29,6 +29,7 @@ Update methods are specified using the following pattern: itself. - The method **should** support partial resource update, and the HTTP verb **should** be `PATCH`. +- The operation **must** have [strong consistency][]. {% tab proto %} @@ -190,7 +191,6 @@ rpc UpdateBook(UpdateBookRequest) returns (aep.api.Operation) { {% endtabs %} -### Create or update If the service uses client-assigned resource paths, `Update` methods **may** expose a `bool allow_missing` field, which will cause the method to succeed in @@ -229,6 +229,50 @@ More specifically, the `allow_missing` flag triggers the following behavior: The user **must** have the update permissions to call `Update` even with `allow_missing` set to `true`. +If the service uses client-assigned resource paths, `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): + +{% tab proto %} + +```proto +message UpdateBookRequest { + // The book to update. + // + // The book's `path` 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; +} +``` + +{% tab oas %} + +**Note:** OAS example not yet written. + +{% endtabs %} + +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. +- 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`. + ### Etags An API may sometimes need to allow users to send update requests which are @@ -312,7 +356,6 @@ unless `allow_missing` is set to `true`. [aep-203]: ./0203.md [create]: ./0133.md [errors]: ./0193.md -[management plane]: ./0111.md#management-plane [permission-denied]: ./0193.md#permission-denied [state fields]: ./0216.md [strong consistency]: ./0121.md#strong-consistency diff --git a/aep/general/0135/aep.md.j2 b/aep/general/0135/aep.md.j2 index aa956ac1..fab1edda 100644 --- a/aep/general/0135/aep.md.j2 +++ b/aep/general/0135/aep.md.j2 @@ -17,10 +17,10 @@ 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. +The method **must** 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: @@ -230,7 +230,6 @@ exist, the service **must** error with `404 Not found` (`NOT_FOUND`). [aep-203]: ./0203.md [aep-214]: ./0214.md [aep-216]: ./0216.md -[management plane]: ./0111.md#management-plane [strong consistency]: ./0121.md#strong-consistency [etag]: ./0134.md#etags [RFC 9110]: https://www.rfc-editor.org/rfc/rfc9110.html#name-delete diff --git a/aep/general/0154/aep.md.j2 b/aep/general/0154/aep.md.j2 index 8e6c3f68..8b615a50 100644 --- a/aep/general/0154/aep.md.j2 +++ b/aep/general/0154/aep.md.j2 @@ -51,7 +51,7 @@ current ETag. If the `If-Match` header value does not match the ETag, the service **must** reply with an HTTP 412 error. If the user omits the `If-Match` header, the service **should** permit the -request. However, services with strong consistency or parallelism requirements +request. However, services with [strong consistency][] or parallelism requirements **may** require users to send ETags all the time and reject the request with an HTTP 400 error if it does not contain an ETag. @@ -113,3 +113,4 @@ not equivalent to the old one). - **2019-09-23**: Changed the title to "resource freshness validation". [rfc 7232]: https://tools.ietf.org/html/rfc7232#section-2.3 +[strong consistency]: ./0121.md#strong-consistency