Name: Update Endpoints
Status: approved
Created: 2023-01-10
Updated: 2023-10-27

Update Endpoints (#134)

PATCH

Endpoints used to update an entity should use PATCH as the verb rather than PUT. This allows for partial updates of the resource. (We require users to use the POST endpoint for entity creation).

PATCH endpoints must implement a derivative of JSON Merge Patch as defined by RFC 7396 with the following clarifications:

  • If the Content-Type request header is not application/json, the PATCH operation must return 400.
  • If an unknown field is provided, the entire PATCH operation must return 400 with the unknown field described in the invalid_parameters extension.
  • If a read-only field is provided, the entire PATCH operation must return 400 with the read-only field described in the invalid_parameters extension.
  • Nested object fields MUST be recursively patched.
  • If the value of a field in the patch document is set to null and...
    • If the property is non-required, then remove the property from the object.
    • If the property is within a schema-less object, then remove the property from the object.
    • If a property is required and nullable, then set the value of the property to null.
    • If a property is required and non-nullable, then return 400 with the required property described in the invalid_parameters extension.

Examples

Given the following example JSON document:

{
"a": "b",
"c": {
"d": "e",
"f": "g"
}
}

If we apply the following changes:

PATCH /target HTTP/1.1
Host: example.org
Content-Type: application/json

{
"a":"z",
"c": {
"f": null
}
}

The preferred JSON response would include any nullified fields that are defined in the entity's schema:

{
"a": "z",
"c": {
"d": "e",
"f": null
}
}

An acceptable JSON response would be to leave out null fields, but this should be the exception, not the rule, for Kong APIs:

{
"a": "z",
"c": {
"d": "e"
}
}

Detailed Example

Given the following JSON document:

{
"attr_1": "Sample Entity",
"attr_2": false,
"attr_3": {
"sub_attr_1": "red",
"sub_attr_2": 1337
},
"tags": [
"tag_1",
"tag_2"
],
"labels": {
"key_1": "val_1",
"key_2": "val_2"
}
}
  1. Modifying a value:

    Change "Sample Entity" to "Updated Entity":

    { "attr_1": "Updated Entity" }
  2. Adding a new field:

    Add "attr_4": "New Attribute":

    { "attr_4": "New Attribute" }
  3. Deleting a field:

    Remove "attr_2" by setting it to null:

    { "attr_2": null }
  4. Modifying a nested field:

    Change "sub_attr_1" to "blue" in "attr_3":

    { "attr_3": { "sub_attr_1": "blue" } }
  5. Replacing an array:

    Replace the tags array with a new one containing "tag_3" and "tag_4":

    { "tags": ["tag_3", "tag_4"] }

    Replace the tags array with an empty array:

    { "tags": [] }
  6. Modifying a field in an object:

    Change label "key_1": "val_1" to the "key_1": "val_one":

    { "labels": { "key_1": "val_one" } }
  7. Adding a new field to an object:

    Add a new label "key_3": "val_3" to the labels object:

    { "labels": { "key_3": "val_3" } }
  8. Deleting a field from an object:

    Remove the label "key_2": "val_2" from the labels object:

    { "labels": { "key_2": null } }

    Remove all labels from the labels object:

    { "labels": { "key_1": null, "key_2": null } }
  9. No op:

    The following patch requests perform no updates.

    {}
    { "labels": {} }
    { "attr_3": {} }
    hello

Exceptions

PUT

In exceptional cases, PUT endpoints may be provided instead of PATCH. PUT endpoints are advised when the full entity representation is required to validate the data sent in the request (ex: conditional entity representations based on a type property discriminator).