-
Notifications
You must be signed in to change notification settings - Fork 39
Patching resources
Patch was implemented as defined in RFC7644 section 3.5.2 but some parts of patch were not described or just vague which is why this page shall demonstrate how patch within this implementation is handled.
NOTE:
In case that a patch-operation is executed the patch-operation will call the get-resource-method and will then execute the patch operation on the returned resource. Eventually the update method is called with the patched resource.
In case that the client uses either the add or the replace operation and omits the path attribute only a single value is allowed which must be a complex json node that describes the resource itself. In this case there are only a few differences between add and replace:
- In case of simple attributes as "userName" or "locale" there is no difference between add and replace
- In case of simple array types the both operations do exactly what you would expect:
- add: adds the given values to the array
- replace: replaces the whole array with the values in the patch operation
- In case of complex types e.g. "name":
- add: adds the single inner simple attributes from the given value into the already existing complex node.
- replace: replaces the whole complex node
- In case of multi valued complex types e.g. "emails":
- add: adds the given complex nodes to the emails-array
- replace: replaces the whole array with the given email-representations
But the more interesting part is if a path-attribute has been given. This has been seperated into two cases
- simple path values e.g.: "userName" or "name.givenName" or "emails.value"
- filter path values e.g.: "name[givenName eq "Norris"].familyName or "emails[displayName sw "Kn"]"
We will start with the first case:
The short description is that this case behaves almost exactly as the way without a path attribute. The difference here is that dependent on the target type several values are allowed or not
imagine the following request
{
"schemas" : [ "urn:ietf:params:scim:api:messages:2.0:PatchOp" ],
"Operations" : [ {
"path" : "userName",
"op" : "add",
"value" : [ "chuck" ]
} ]
}
- "userName" present
- the attribute is replaced
- "userName" not present
- the attribute is added
{
"schemas" : [ "urn:ietf:params:scim:api:messages:2.0:PatchOp" ],
"Operations" : [ {
"path" : "name",
"op" : "add",
"value" : [ "{\"givenName\": \"Carlos\", \"familyName\": \"Norris\"}" ]
} ]
}
- "name" present
- the values "givenName" and "familyName" are added to the existing name-attribute
- "name" not present
- the name attribute is added with the two values "givenName" and "familyName"
- "name" present
- the whole name attribute is replaced so that only a name attribute with the values "givenName" and "familyName" remains
- "name" not present
- the name attribute is added with the two values "givenName" and "familyName"
{
"schemas" : [ "urn:ietf:params:scim:api:messages:2.0:PatchOp" ],
"Operations" : [ {
"path" : "name.givenName",
"op" : "add",
"value" : [ "Carlos" ]
} ]
}
- "name" not present
- the attribute name is created
- "name.givenName" present
- the attribute is replaced
- "name.givenName" not present
- the attribute is added
{
"schemas" : [ "urn:ietf:params:scim:api:messages:2.0:PatchOp" ],
"Operations" : [ {
"path" : "emails",
"op" : "add",
"value" : [ "{\"value\": \"[email protected]\", \"type\": \"work\"}",
"{\"value\": \"[email protected]\", \"type\": \"home\"}" ]
} ]
}
- "emails" present
- two new complex email-nodes are added to the "emails"-attribute array
- "emails" not present
- the emails attribute is created and the new email-nodes are added to it
- "emails" present
- the whole emails-array is exchanged for the given two new email-nodes
- "emails" not present
- the emails attribute is created and the new email-nodes are added to it
{
"schemas" : [ "urn:ietf:params:scim:api:messages:2.0:PatchOp" ],
"Operations" : [ {
"path" : "emails.type",
"op" : "add",
"value" : [ "work" ]
} ]
}
- "emails" not present
- a bad request is returned because no email nodes are present in the "emails" attribute
- "emails.type" present
- the attribute is replaced within each existing email-node
- "emails.type" not present
- the attribute is added within each existing email-node
In the standard resources defined in RFC7643 "User" and "Group" you will not find any declarations of simple-arrays. But imagine the following patch operation
{
"schemas" : [ "urn:ietf:params:scim:api:messages:2.0:PatchOp" ],
"Operations" : [ {
"path" : "multivalued.stringarray",
"op" : "add",
"value" : [ "hello", "world" ]
} ]
}
- "multivalued" not present
- a bad request is returned because there are no complex nodes to which an attribute could be added
- "multivalued.stringarray" present
- the values "hello" and "world" are added to each existing "multivalued.stringarray"-node
- "multivalued.stringarray" not present
- a new "stringarray" attribute is created in each existing "multivalued"-node with the values "hello" and "world"
- "multivalued" not present
- a bad request is returned because there are no complex nodes on which an attribute could be replaced
- "multivalued.stringarray" present
- the "stringarray" attributes of each existing "multivalued"-node is replaced with a new array containing the two values "hello" and "world"
- "multivalued.stringarray" not present
- a new "stringarray" attribute containing the two values "hello" and "world" is created for each existing "multivalued"-node
this have been the easy patch operations. Now we are coming to the more complex operations with filter-expressions
{
"schemas" : [ "urn:ietf:params:scim:api:messages:2.0:PatchOp" ],
"Operations" : [ {
"path" : "userName[type eq \"work\"]",
"op" : "add",
"value" : [ "chuck" ]
} ]
}
- throws simply a bad request because its an invalid filter. The attribute "userName" is a simple attribute and therefore an attribute with the scheme "userName.type" does not exist
{
"schemas" : [ "urn:ietf:params:scim:api:messages:2.0:PatchOp" ],
"Operations" : [ {
"path" : "name[givenName eq \"work\"].familyName",
"op" : "add",
"value" : [ "chuck" ]
} ]
}
- "name" not present
- bad request is returned for "no target"
- "name.givenName" not present
- bad request is returned for "no target"
- "name.givenName" present and filter matches
- the attribute "familyName" is added to the name-attribute
- "name.givenName" present and filter does not match
- bad request is returned for "no target"
{
"schemas" : [ "urn:ietf:params:scim:api:messages:2.0:PatchOp" ],
"Operations" : [ {
"path" : "emails[value eq \"123456\"].type",
"op" : "add",
"value" : [ "home" ]
} ]
}
- "emails" not present
- a bad request is returned for no target was found
- "emails.value" present and filter matches
- the type-value of all nodes that have a "value" attribute with "123456" will be changed to "home"
- "emails.value" present and filter does not match
- a bad request is returned for no target was found
{
"schemas" : [ "urn:ietf:params:scim:api:messages:2.0:PatchOp" ],
"Operations" : [ {
"path" : "emails[value eq \"[email protected]\"]",
"op" : "replace",
"value" : [ "{\"value\": \"[email protected]\", \"type\": \"work\"}" ]
} ]
}
- "emails" not present
- a bad request is returned for no target found
- "emails.value" present and filter matches
- all matching nodes will have the attributes value and type added/replaced
- "emails.value" present and filter does not match
- a bad request is returned for no target found
In the standard resources defined in RFC7643 "User" and "Group" you will not find any declarations of simple-arrays. But imagine the following patch operation
{
"schemas" : [ "urn:ietf:params:scim:api:messages:2.0:PatchOp" ],
"Operations" : [ {
"path" : "multivalued[stringarray eq \"hello\" and stringarray eq \"world\"].stringarray",
"op" : "add",
"value" : [ "dooms", "day" ]
} ]
}
- "multivalued" not present
- bad request is returned for no target found
- "multivalued.stringarray" present and filter matches [stringarray must contain a value "hello" and a value "world"]
- the values "dooms" and "day" will be added to the stringarray attribute
- "multivalued.stringarray" present and filter does not match
- bad request is returned for no target found
- "multivalued.stringarray" not present
- bad request is returned for no target found
- "multivalued" not present
- bad request is returned for no target found
- "multivalued.stringarray" present and filter matches [stringarray must contain a value "hello" and a value "world"]
- the stringarray replace all its values for the two values "dooms" and "day"
- "multivalued.stringarray" present and filter does not match
- bad request is returned for no target found
- "multivalued.stringarray" not present
- bad request is returned for no target found