JSON PATCH

JSON PATCH is a standard specified by RFC 6902 for modifying a resource "document" based on a URI and the HTTP PATCH method.

See: https://tools.ietf.org/html/rfc6902

The JSON PATCH message contains an array of operations that are to be applied in sequence to a resource. The message fails as soon as any one of the operations fails and so all must succeed for the modifications to be persisted.

There are several different operations covered in the specification:

  • add
  • remove
  • replace
  • move
  • copy
  • test

The "move" and "copy" operations are not supported in this release.

Operation objects MUST have exactly one "op" member, whose value indicates the operation to perform. Its value MUST be one of "add", "remove", "replace", or "test"; other values are errors. The semantics of each supported operation is defined in a section below.

Additionally, operation objects MUST have exactly one "path" member. That member's value is a string containing a JSON-Pointer value https://tools.ietf.org/html/rfc6901 that references a location, relative to the target URI, within the target resource (the "target location") where the operation is performed.

To access an item in an array, the JSON Pointer specification (RFC 6901) requires an array index. The index is zero-based which means the first item in the array is 0 (zero) and the last index is (array size - 1). The resources available in the OTM REST API do not always maintain a fixed array index for child resources and so this approach may be of limited use. Additionally, the OTM REST API uses a Collection Resource to hold arrays of child resources and so to align more closely with how a client application would reference a child resource in a target URI, the OTM REST API implementation of JSON Pointer specification extends the basic array index method.

A Collection Resource is a JSON object which can contain an "items" array and a "links" array.

Using the standard JSON-Pointer syntax, a "path" member value might be:

"path" : "childName/items/0/childProperty"

This will target the "childProperty" in the first child resource for the "childName" child resource.

Because you may not be aware of the particular index for the target item (i.e. may not have performed a preceding GET request) a more natural way to target a child resource is to specify the GID, in the same was as is done in target URIs:

"path" : "childName/childId/childProperty"

This will target the "childProperty" in the child resource for the "childName" child resource with a primary key of "childId".

Note:

If a GID inside a path contains a slash character "/" e.g. if it relates to a sub-domain, the slash character should be encoded as "~1".

Lastly, query criteria similar to the "q" query parameter (used to filter GET request) can be used to decide which child resource to target. The query criteria string is contained within square brackets: [...query string...].

"path" : "childName[a eq \"b\"]/childProperty"

This will target the "childProperty" for the "childName" child resource which has the value "b" for the property "a".

Note:

The query criteria supported for a JSON PATCH path will initially have a few limitations:

  • They only support "and".
  • They only support "eq".
  • They only support attributes of type String.
  • The predicates specified in square brackets should only be simple combinations of conditions. Complex conditions that rely on operator precedence may not produce the expected results. In these cases it may be necessary to execute a GET with the relevant "q" query string to first retrieve the results and then to apply the JSON PATCH by accessing the items directly using one of the other "path" formats.

The values in an operation can be any valid JSON property value except for a JSON array. There is no valid case where an operation containing an array of properties or objects can be applied to a resource.

Child resource values must either be specified as a Singular Resource or as a Collection Resource. Both of these are structured as JSON objects. The choice of which value type is valid will be based on the operation "path".

See operation examples below.

add

The "add" operation performs one of the following functions, depending upon the target URI:
  • If the target location specifies an array index, a new value is inserted into the array at the specified index.
  • If the target location specifies an object member that does not already exist, a new member is added to the object.
  • If the target location specifies an object member that does exist, that member's value is replaced.

Example 1

{ "op": "add", "path": "/a/b/c", "value": 42 }

The "path" property provides a path to the property "c". If "c" does not exist in the target resource then it will be added with the value "42". If "c" does exist and has a value, then the value will be modified to be "42". Implicit in this operation is that the type of the "value" and the type of the property in the resource MUST match, i.e. "c" is expected to be an integer property type.

Example 2

{ "op": "add", "path": "/remarks/1", "value":{"remarkQualGid":"REM", "remarkText":"123456"} }

The "path" property provides a path to the "remarks" child resource with an ID (remarkSequence) of 1. If a remark does not exist with this ID in the target resource then it will be added. If the remark does exist, then the "remarkQualGid" and "remarkText" properties will be updated with the values from the request.

remove

The "remove" operation removes the value of a (non-required) property at the target URI. The target property MUST exist. The format of an example operation is as follows:

{ "op": "remove", "path": "/a/b/c"}

The "path" property provides a path to the property "c". If "c" does not exist in the target resource, then an error will be reported. If "c" does exist then its value is set to "null" as long as it is not a required property.

replace

The format of the replace operation is as follows:

{ "op": "replace", "path": "/a/b/c", "value": 42 }

The "path" property provides a path to the property "c" for which the value must be modified to be 42. Implicit in this operation is that the type of the "value" and the type of the property in the resource must match. The property at the specified path must exist for the operation to be successful. If the value MAY NOT exist but a new value is still required, then the "add" operation should be used.

For example, to modify the "ownerName" property for an Equipment Type (GID is GUEST.ET_1):

curl -u username:password -X PATCH -H "Content-Type:application/json-patch+json"
-d '[
{ "op" : "replace", "path" : "/ownerName", "value" : "OWNER NAME"}
]'
https://servername.us2.oraclecloud.com/logisticsRestApi/resources/v2/equipments/GUEST.ET_1

To update the totalGrossWeight of the first shipUnits resource in an order release (GID is GUEST.OR_1 returned using the standard array index notation:

curl -u username:password -X PATCH -H "Content-Type:application/json-patch+json"
-d '[
{ "op" : "replace", "path" : "shipUnits/items/0/totalGrossWeight", "value" : {"value": 10, "unit": "LB"}}
]'
https://servername.us2.oraclecloud.com/logisticsRestApi/resources/v2/orderReleases/GUEST.OR_1

To update the totalGrossWeight for a specific shipUnits resource with a particular shipUnitGid (GUEST.SU-GID-1):

curl -u username:password -X PATCH -H "Content-Type:application/json-patch+json"
-d '[
{ "op" : "replace", "path" : "shipUnits/GUEST.SU-GID-1/totalGrossWeight", "value" : {"value": 10, "unit": "LB"}}
]'
https://servername.us2.oraclecloud.com/logisticsRestApi/resources/v2/orderReleases/GUEST.OR_GID-1

If in the previous example the domain was GUEST/CHILD instead of GUEST, then the ID would contain the "/" character and therefore require encoding. The path member should then be:

curl -u username:password -X PATCH -H "Content-Type:application/json-patch+json"
-d '[
{ "op" : "replace", "path" : "shipUnits/GUEST~1CHILD.SU-GID-1/totalGrossWeight", "value" : {"value": 10, "unit": "LB"}}
]'
https://servername.us2.oraclecloud.com/logisticsRestApi/resources/v2/orderReleases/GUEST~1CHILD.OR_GID-1

The example below uses query criteria to set the remarkText to "AMERICAN" where the remarkQualGid is "AIRLINE" on the shipUnits resource whose GID is "GUEST.MYOR-001".

curl -u username:password -X PATCH -H "Content-Type:application/json-patch+json"
-d '[
{ "op": "replace", "path": "/shipUnits[shipUnitGid eq \"GUEST.MYOR-001\"]/remarks[remarkQualGid eq \"AIRLINE\"]/remarkText", "value": "AMERICAN" }
]'
https://servername.us2.oraclecloud.com/logisticsRestApi/resources/v2/orderReleases/{orderReleaseGid}

test

The format of the test operation is as follows:

{ "op": "test", "path": "/a/b/c", "value": 42 }

The message is identical to the format for the "replace" operation except that the "test" only succeeds if the value at the specified path is identical to the value in the operation. It does not modify any value. In this way conditional modifications can be controlled. For example, if a JSON PATCH message contains two operations, a "test" followed by a "replace", then the "replace" will only be attempted if the "test" operation succeeds. Multiple test operations are supported and may be preferable to overly complex criteria on a single "test" operation.

For example, to modify the "ownerName" property for an Equipment Type if, and only if, it was previously "OLD OWNER NAME":

curl -u username:password -X PATCH -H "Content-Type:application/json-patch+json"
-d '[
{ "op" : "test", "path" : "/ownerName", "value" : "OLD OWNER NAME"},
{ "op" : "replace", "path" : "/ownerName", "value" : "NEW OWNER NAME"}
]'
https://servername.us2.oraclecloud.com/logisticsRestApi/resources/v2/equipments/{equipmentGid}