Update Endpoints (#134)

From 2023-01-10 until 2025-04-08, Kong's guidance was to provide PATCH endpoints only. This was changed on 2025-04-08 to require PATCH and PUT for all endpoints. This is not being retroactively enforced for existing APIs.

Both PATCH and PUT operations are required1 for entities. PATCH operations are user-friendly for end users that are directly implementing the API in their applications, and PUT operations are required to build fully declarative tooling.

1 If you believe that your API can't support both operations based on the exceptions listed below, seek approval in the #api-design channel in Slack

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 in OpenAPI specifications should use the operation ID update -<entity> e.g. update-control-plane.

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 Examples

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"
}
}

Add a value

Add "attr_4": "New Attribute" :

{ "attr_4": "New Attribute" }

Update a value

Change "Sample Entity" to "Updated Entity" :

{ "attr_1": "Updated Entity" }

Add a nested field

Add a new attribute, sub_attr_3 to attr_3:

{ "attr_3": { "sub_attr_3": "yellow" } }

Update a nested field

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

{ "attr_3": { "sub_attr_1": "blue" } }

Setting a nullable field to a null value

{ "attr_3": null }

Replace an array

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

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

Empty an array

{ "tags": [] }

Delete a field from an object

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

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

Remove all fields from an object

You must provide all existing keys and specify a null value to remove all of them:

{ "labels": { "key_1": null, "key_2": null } }

No-op requests

The following patch requests perform no updates.

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

PUT

PUT can either create or replace an entity based on rfc-7231. In the case of a creation, the endpoint MUST return 201. When the entity is replaced, the endpoint MUST return 200.

PUT endpoints in OpenAPI specifications should use the operation ID upsert-<entity> e.g. upsert-control-plane.

Example

# Example route
PUT /entity/{id}

PUT /entity/123 => HTTP 201. entity created
PUT /entity/123 => HTTP 200. entity replaced

Security: Enumeration risks

When the endpoint supports the creation of an entity the implementation MUST ensure the ID of the resource passed is only unique within its parent and organization. This implies that these IDs cannot be a globally unique primary key within a relational database schema. Otherwise it makes entity enumeration possible.

See example:

# Example routes
PUT /parent/{id-1}
PUT /parent/{id-1}/child/{id-2}

# Organization A
PUT /parent/1 => creates parent:1 in organization A

# Organization B
PUT /parent/1 => creates parent:1 in organization B

# Organization A
PUT /parent/1/child/2 => creates child:2 in parent 1 in organization A
PUT /parent/3/child/2 => creates child:2 in parent 3 in organization A

# Organization B
PUT /parent/1/child/2 => creates child:2 in parent 1 in organization B
PUT /parent/3/child/2 => creates child:2 in parent 3 in organization B

In the example above we see that none of the IDs created by PUT requests collides between orgs or parent entities.

Exceptions

PATCH is not suitable

PATCH operations may be omitted 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).