diff --git a/db-controller.js b/db-controller.js index 8e7ed7b5..f794278d 100644 --- a/db-controller.js +++ b/db-controller.js @@ -982,6 +982,9 @@ const id = async function (req, res, next) { res.set("Cache-Control", "max-age=86400, must-revalidate") //Support requests with 'If-Modified_Since' headers res.set(utils.configureLastModifiedHeader(match)) + // Include current version for optimistic locking + const currentVersion = match.__rerum?.isOverwritten ?? "" + res.set('Current-Overwritten-Version', currentVersion) match = idNegotiation(match) res.location(_contextid(match["@context"]) ? match.id : match["@id"]) res.json(match) diff --git a/public/API.html b/public/API.html index 1eaebd7a..a3a56e83 100644 --- a/public/API.html +++ b/public/API.html @@ -809,13 +809,19 @@

Overwrite

RERUM allows the Generator of a record to overwrite that record. An error will be returned if the agent encoded in the request "Authorization" access token does not match the agent of the existing record. - Replace a record using a reference to its internal RERUM id and receive the Location URI for the resulting record as a response header and the complete record as the response body. - This will have the effects of update, set, and unset actions. New keys will be created and keys not present in the request will not be present in the resulting record. - The record is replaced in place, or overwritten, and so the @id will not change and the history connected with this record will not be altered. The __rerum.isOverwritten property will be set to the date and time of the overwrite.

+

+ This endpoint supports optimistic locking, if requested. Including the "If-Overwritten-Version" header with the + value of the __rerum.isOverwritten property of the + record will cause the request to fail if the record has been overwritten since that time. + This is useful for preventing overwriting a record that has been changed by another agent, colliding within an + application that rapidly requests overwrites of the same object, or if an object is held in memory or cache for a + long time prior to the overwrite. Omitting the "If-Overwritten-Version" header or __rerum.isOverwritten + property will cause the request to succeed regardless. +

@@ -865,6 +871,12 @@

Overwrite

+

+ In the case of an optimistic locking failure, the response will be a 409 Conflict with a + body containing the current version of the document, in case you would like to automate a + retry of the overwrite request. +

+

Here is what the response resp looks like:

@@ -878,12 +890,11 @@ 

Overwrite

}

- Note that resp.headers.get("location") will return "https://devstore.rerum.io/v1/id/abcdef1234567890" + Note: resp.headers.get("location") will return "https://devstore.rerum.io/v1/id/abcdef1234567890"

- Note that the @id and __rerum.history properties of the original record "https://devstore.rerum.io/v1/id/abcdef1234567890" have not changed. This is the difference between /update and /overwrite. Be careful. + Note: the @id and __rerum.history properties of the original record "https://devstore.rerum.io/v1/id/abcdef1234567890" have not changed. This is the difference between /update and /overwrite. Be careful.

-