Skip to content

Commit

Permalink
fix(update): add json-merge-patch guidance for HTTP
Browse files Browse the repository at this point in the history
After offline discussion, it was agreed upon that IETF RFC 7396 (JSON Merge Patch) is the more sensible choice for a partial update on an HTTP+JSON API. The rationale includes:

- can generally be expressed via protobuf field masks.
- aligns with the AEPs usage of resource-oriented guidance.
- aligns with an existing IETF standard, which as already been widely adopted.
  • Loading branch information
toumorokoshi committed Nov 19, 2024
1 parent 14c600b commit 898062f
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 4 deletions.
37 changes: 37 additions & 0 deletions aep/general/0134/aep.md.j2
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,11 @@ Update methods implement a common request pattern:

{% sample '../example.oas.yaml', '$.paths./publishers.post.requestBody' %}

- The method **must** adhere to the behavior specified in [IETF RFC 7396 - Json
Merge Patch][].
- The method **must** support MIME types `application/merge-patch+json` to
adhere to IETF RFC 7396.

{% endtabs %}

### Responses
Expand Down Expand Up @@ -167,6 +172,37 @@ If a rating were set on a book and the existing `PUT` request were executed, it
would wipe out the book's rating. In essence, a `PUT` request unintentionally
would wipe out data because the previous version did not know about it.

### FieldMasks in proto and json merge-patch in HTTP

AEP recommends a specific diverence in behavior between the proto and the HTTP
interfaces. Specifically:

- The inclusion of the `update_mask` in the proto variant, requiring the user to
explicitly specify fields to be updated.
- The usage of [IETF RFC 7396 - Json Merge Patch][IETF RFC 7396] for HTTP APIs.

This divergence in behavior is intentional, and exists for the following reasons:

1. The update mask is a proto-specific concept, due to the lack of ability
across all proto versions to differentiate if the user has explicitly
populated a field or not. JSON has the ability to express whether a field is
present (by omitting it from the JSON payload). Ultimately, this allows the
field mask + proto pair and json to be translatable.
2. RFC 7396 is a popular and well-understood standard for HTTP. Introducing a
new standard for HTTP would have made the AEP HTTP variant less idiomatic.
3. For HTTP-proto bindings, there is a way to generate the proto field mask from
the fields present in the JSON request. This is what is recommended in the
[API Design Patterns book, section 8.2
](https://www.oreilly.com/library/view/api-design-patterns/9781617295850/),
describing the Google AIPs from which AEP-134 is forked. Implementations of
gateway-grpc proto bindings such as
[gateway-grpc](https://grpc-ecosystem.github.io/grpc-gateway/docs/mapping/patch_feature/)
support this translation.

Therefore, given the ability of these two different patch mechanisms to
interoperate while maintaining idiomatic practices, this divergence was
concluded to be the least worst option.

### Create or Update

If the service uses client-assigned resource paths, `Update` methods **may**
Expand Down Expand Up @@ -310,4 +346,5 @@ and omit the rest. APIs that do this **must** document this behavior.
[strong consistency]: ./0121.md#strong-consistency
[required]: ./0203.md#required
[optional]: ./0203.md#optional
[IETF RFC 7396]: https://datatracker.ietf.org/doc/html/rfc7396
<!-- prettier-ignore-end -->
8 changes: 4 additions & 4 deletions aep/general/example.oas.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -202,14 +202,14 @@ paths:
type: string
requestBody:
content:
application/json:
application/merge-patch+json:
schema:
$ref: '#/components/schemas/publisher'
required: true
responses:
'200':
content:
application/json:
application/merge-patch+json:
schema:
$ref: '#/components/schemas/publisher'
description: Successful response
Expand Down Expand Up @@ -311,14 +311,14 @@ paths:
type: string
requestBody:
content:
application/json:
application/merge-patch+json:
schema:
$ref: '#/components/schemas/book'
required: true
responses:
'200':
content:
application/json:
application/merge-patch+json:
schema:
$ref: '#/components/schemas/book'
description: Successful response
Expand Down

0 comments on commit 898062f

Please sign in to comment.