Skip to content

Update

In REST APIs, it is customary to make a PATCH request to a resource’s URI (for example, /v1/publishers/{publisherId}/books/{bookId}) in order to update that resource.

Resource-oriented design AEP-121 honors this pattern through the Update action (which mirrors the REST PATCH behavior). These actions accept the URI representing that resource and return the resource.

Also see the apply action, with guidance on how to replace resources.

APIs should provide an update action for resources unless it is not valuable for users to do so. The purpose of the update action is to make changes to the resources without causing side effects.

  • The action should support partial resource update, and the HTTP method must be PATCH.
    • PATCH must follow the guidelines in AEP-68.
  • The operation must have strong consistency.
  • It must be used to partially update a resource at a known URI.
  • Some resources take longer to be updated than is reasonable for a regular API request. In this situation, the API should use a long-running operation.
  • They must not modify read-only or server-managed fields (e.g., createdTime).

Update operations must be made by sending a PATCH request to the resource’s canonical URI path:

PATCH /v1/publishers/{publisherId}/books/{bookId}

Update actions implement a common request pattern:

  • The action must use the JSON Merge Patch with fieldMask as the update strategy.
    • It must adhere to the behavior specified in RFC 7396 JSON Merge Patch.
  • The server must support MIME type application/merge-patch+json to adhere to RFC 7396.
  • The request body must be a partial representation of the resource; only the fields to be updated. It must include a request body that describes the changes to be applied.
  • If read-only fields are included in the request, they should be ignored or return 400 Bad Request, depending on your API’s semantics.
  • Unrecognized fields may be ignored or may cause a 400 Bad Request, depending on the API’s semantics.
    • This must be documented.
  • Fields omitted from the request must remain unchanged in the resource.

APIs must use the RFC 7396 JSON Merge Patch with field masking approach for Update operations. Field masking uses a simple partial JSON object with an explicit field mask parameter to indicate which fields to update.

  • The MIME Type of the request must be application/merge-patch+json.
  • The field mask must be provided as a query parameter named updateMask, containing all fields to be updated ( e.g., updateMask=field1,field2,nested.field).
  • If no updateMask is provided, the request should return 400 Bad Request to ensure explicit intent.
  • Only fields listed in the updateMask must be updated on the resource.
  • Fields present in the request body but not in the updateMask must be ignored.
  • Fields listed in the updateMask but not present in the request body should return 400 Bad Request.
  • To clear a field value, include the field in both the updateMask and the request body with an explicit null value.
  • Array fields must be replaced entirely when updated. A limitation of field masking is that it does not support individual array element updates. To modify an array, include the entire array field in the updateMask and provide the complete new array in the request body.
  • Nested fields should be specified using dot notation (e.g., address.city, contact.email).
    • When updating nested fields, only the specified nested field is modified; sibling fields within the same parent object must remain unchanged.
    • To update multiple fields within a nested object, each field must be listed separately in the updateMask ( e.g., address.city,address.zip).
    • To replace an entire nested object, specify only the parent field in the updateMask (e.g., address). In this case, the entire object is replaced with the provided value.

In the following example, only the name and address.city fields are updated. Any other fields this resource may have (address.street, address.state, email, etc.) remain unchanged.

PATCH /users/456?updateMask=name,address.city
Content-Type: application/merge-patch+json
{
"name": "Bruce Wayne",
"address": {
"city": "Gotham"
}
}
  • On a successful update, the response must return 200 OK.
  • The MIME Type of the response must be application/json. It must not be application/merge-patch+json.

The response body:

  • must be the resource itself. There is no separate response schema.
  • should include the complete representation of the updated resource.
  • must include any fields that were provided unless they are input only.
  • must include any server-generated fields (e.g., id, createdTime, updatedTime).
  • should return the complete updated resource in the response, not just the fields that were modified. This allows clients to see the full result of their changes, including any server-side transformations or computed fields.
  • For bulk update operations, APIs may return a summary or list of IDs/Status objects instead of full resources to improve performance.
paths:
/publishers/{publisherId}/books/{bookId}:
patch:
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/book'
description: Successful response

An Update action must return appropriate error responses. For additional guidance, see Errors and HTTP status codes.

Most common error scenarios:

  • 400 Bad Request should be returned if:
    • the request body is malformed
    • fields are listed in the updateMask but not present in the request body
    • no updateMask query parameter is provided
  • 404 Not Found should be returned if the resource does not exist.
  • 409 Conflict should be returned if the resource could not be updated due to a conflict with the current state of the resource.
  • See authorization checks for details on responses based on permissions.

In general, update actions are intended to update the data within the resource. Update actions should not trigger other side effects. Instead, side effects should be triggered by custom actions.

In particular, this entails that state fields must not be directly writable in update actions.

Updates must be done with a PATCH. Applies must be done with a PUT. See the PATCH and PUT section of AEP-67 for more information.

See etags for more information about adding headers and metadata such as ETag and If-Match for supporting resource freshness validation and other preconditions.

Update actions must not be used to change the ID of a resource. In a REST API, a resource’s ID is a fundamental part of its URI and should be treated as immutable. Changing the ID is considered a bad practice. If the ID must be changed for business or technical reasons, then a new resource must be created using Create or Apply, and the old resource should be deleted.

APIs may provide a redirect from the old URI to the new one using 301 Moved Permanently in requests to the old URI. This ensures clients are aware of the move. The response may also include a Location header pointing to the new URI.

paths:
/publishers/{publisherId}/books/{bookId}:
patch:
description: Update method for book
operationId: updateBook
parameters:
- in: path
name: publisherId
required: true
schema:
type: string
- in: path
name: bookId
required: true
schema:
type: string
- in: query
name: updateMask
required: true
description: >
Comma-separated list of field names to update. Only the fields
listed here will be modified.
schema:
type: array
items:
type: string
enum:
- author.familyName
- author.givenName
- edition
- isbn
- price
- published
style: form
requestBody:
content:
application/merge-patch+json:
schema:
$ref: '#/components/schemas/book'
required: true
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/book'
description: Successful response

Why field masking?

RFC 7396 is a popular and well-understood standard for HTTP. Introducing a new standard would make our APIs less idiomatic.

We’ve added field masking on top of JSON Merge Patch because it provides the optimal balance of simplicity, explicitness, and functionality. The updateMask parameter makes intent completely clear, preventing accidental updates and eliminating ambiguity about which fields are being modified. It also helps to alleviate the null-value ambiguity of plain Merge Patch. Dot notation (e.g., address.city) provides a straightforward way to update specific fields within nested objects.