Image alternative text

Name: Miniput

A resource designed to enable doing a partial update to another resource.

Problem

It is frequently desirable to allow a client to update a subset of information contained in a resource. The HTTP specification does not allow the PUT method to perform partial updates to a resource. The PATCH method can be used to make an incremental changes to a resource, but it requires a specially formatted patch format payload like JSON-Patch or JSON-Merge-Patch. Also, PATCH is not guaranteed to be idempotent.

Solution

Creating "child" resources to represent fragments of another resource allows partial updates of the "parent" resource by doing complete updates of the "child" resource.

Assuming we have a "parent" resource that looks like this,

x
 
1
GET /Contact/2323
2
Host: example.org
3
4
=>
5
6
HTTP/1.1 200 OK
7
Content-Type: application/json
8
Content-Length: ...
9
10
{
11
    "firstname" : "James",
12
    "lastname" : "Bond",
13
    "telephone" : ""
14
}
We can update the telephone number of the contact by doing a PUT to a "child" resource.
x
1
PUT /Contact/2323/telephone
2
Host: example.org
3
Content-Type: text/plain
4
Content-Length: 12
5
6
514-426-0102
7
8
=>
9
10
HTTP/1.1 204 No Content
Retreiving the "parent" resource would give the following,
x
 
1
GET /Contact/2323
2
Host: example.org
3
4
=>
5
6
HTTP/1.1 200 OK
7
Content-Type: application/json
8
Content-Length: ...
9
10
{
11
    "firstname" : "James",
12
    "lastname" : "Bond",
13
    "telephone" : "514-426-0102"
14
}
If it is preferable to return the updated representation from the PUT, it can be done as follows,
x
 
1
PUT /Contact/2323/telephone
2
Host: example.org
3
Content-Type: text/plain
4
Content-Length: 12
5
6
514-426-0102
7
8
=>
9
10
HTTP/1.1 200 OK
11
Content-Location: http://example.org/Contact/2323
12
Content-Type: application/json
13
Content-Length: ...
14
15
{
16
    "firstname" : "James",
17
    "lastname" : "Bond",
18
    "telephone" : "514-426-0102"
19
}
The Content-Location header is required in this case because the returned representation does not come from the resource that is the target of the PUT.

Discussion

This solution is effective for making updates to a limited number of fragments of a resource. However it is less than ideal for a general purpose way of doing partial updates as it requires the creation of a resource for all combinations of possible partial updates.

As PUT is used to make these changes, the operation is idempotent and unsafe. One risk of using this approach is that cache invalidation becomes more tricky. HTTP caches will naturally invalidate representations when they see an inbound PUT on a resource. However, because a Miniput is actually updating the "parent" different resource, the cache will not know to invalid the "parent" resource. This issue can be addressed using cache-invalidation link headers for caches that support that technique.

One useful characteristic of this approach is that "child" resources can use a very simple media type for performing the update. Frequently the text/plain media type is suffient for partial updates that only update a single property.

An additional benefit of creating these very finely grained resources for doing updates is that they can also be used for retrieving just a single piece of information about a resource. However, these benefits can quickly be lost if there are multiple pieces of information required and a client starts making multiple round-trips to retrieve that information.

Related

Bucket, Whack-a-mole

Acknowledgements

Thanks to Alain Gaeremynck for catching my careless typos!