iotagent-node-lib icon indicating copy to clipboard operation
iotagent-node-lib copied to clipboard

Question: Adding NGSI-LD 1.6.1 PATCH support

Open jason-fox opened this issue 2 years ago • 11 comments

Unlike #1258 adding merge PATCH support will prove a bit tricker.

endpoints
  1. Not all IoT Agents will want to support the merge PATCH endpoint at all (though it is useful for advanced actuation)
  2. Not all IoT Agents will want to support null to indicate the removal of a target member - see line 2689
None of the members described admit a null value directly, as when a JSON-LD processor
encounters null, the associated entry or value is always removed when expanding the JSON-LD
document. However in the context of a update or merge operation (see clauses 5.5.8 and 5.5.12), a
null encoded as a JSON literal {"@type": "@json", "@value": null } is a valid JSON token and
shall be used to indicate the removal of a target member. In all other cases implementations shall
raise an error of type BadRequestData if a null or JSON literal null value is encountered. 

Before raising a PR to cover this, I thought I'd raise an issue for discussion how best to handle this. I guess they are new config parameters for the server:

contextBroker: {
        host: '192.168.1.1',
        port: '1026',
        ngsiVersion: 'ld',
        jsonLdContext: 'http://context.json-ld'
},
server: {
        port: 4041
},

Becomes

contextBroker: {
        host: '192.168.1.1',
        port: '1026',
        ngsiVersion: 'ld',
        jsonLdContext: 'http://context.json-ld'
},
server: {
        port: 4041,
        supportNull: true,
        supportMerge: true
},

If so I assume that is just another Docker ENV param and nothing is needed for provisioning devices or services.

jason-fox avatar Jul 12 '22 07:07 jason-fox

Probably separate supportNull and supportMerge into different sections makes sense since it is a NGSL-LD specific behavior in the configuration. In case of using mixed mode this can be confusing (it would be supported by v2 endpoint?).

I propose to use a new key into config file. As an example, ldFlavours or ldConfig as name for the new key.

mapedraza avatar Jul 12 '22 09:07 mapedraza

The point is that this is actually the north port NGSI-LD capability of the IoT Agent itself ( server ) and by implication the underlying IoT Agent in NGSI-LD mode. Something like this:

server: {
        port: 4041,
        ldCapability : {
           supportNull: true,
           supportMerge: true
       }
},

jason-fox avatar Jul 12 '22 09:07 jason-fox

Imagine you have something like an NGSI-LD OneM2M bridge or an NGSI-LD ROS2 IoT Agent. In this case it makes sense that the removal of a target member aligns to removing the relevant container in OneM2M or unsubscribing from a given ROS2 topic. Merge Patch would need to be

  • get the latest state from the southport as JSON
  • apply IETF JSON Merge Patch
  • push the actuation back down into the southport.

Now this sort of complex operation doesn't make any sense for simpler protocols, so wouldn't need to be supported, but would be really, really useful in robotics.

jason-fox avatar Jul 12 '22 09:07 jason-fox

The point is that this is actually the north port NGSI-LD capability of the IoT Agent itself ( server ) and by implication the underlying IoT Agent in NGSI-LD mode. Something like this:

server: {
        port: 4041,
        ldCapability : {
           supportNull: true,
           supportMerge: true
       }
},

This alternative is fine as long as it does not impact existing codebase for v2 endopoint.

mapedraza avatar Jul 12 '22 09:07 mapedraza

Next question on advanced actuations. The NGSI-LD supports multiple values for the same attribute separated by a datasetId for example:

{
  "lampColor": [
    {
      "type": "Property",
      "value": ["green", "55 secs"],
      "datasetId": "urn:ngsi-ld:Property:do-this"
    },
    {
      "type": "Property",
      "value": ["red", "10 secs"],
      "datasetId": "urn:ngsi-ld:Property:then-do-this"
    }
  ],
} 

Could be used to send sequential commands to an endpoint. At the moment each Attribute is defined as:

attributes.push({
                type: 'Property',
                value,
                name: attribute
 });

Could this be extended to add an optional datasetId? Is this something to be added to the NGSI-v2 handlers as well?

jason-fox avatar Jul 14 '22 10:07 jason-fox

Second question on advanced actuations. There are some commands in robotics which rely on the metadata as well as the command itself, for example move by X,Y,Z given set of a reference coordinates:

{
  "moveTo": {
    "type": "Property",
    "value": [1,2,3],
    "qos": { "type": "Property", "value": 1},
    "referenceCoords": { "type": "Property", "value": [1,2,3]},
    "format": { "type": "Property", "value": "W3C"}
  }
}

Could Attribute be extended to add a metadata element. Since metadata is supported by the v2 API, I assume this is something to be added to the NGSI-v2 handler as well.

{
  "moveTo": {
    "type": "Array",
    "value": [1,2,3],
    "metadata": {
        "qos": { "type": "Number", "value": 1},
        "referenceCoords": { "type": "Array", "value": [1,2,3]},
        "format": { "type": "Text", "value": "W3C"}
     }
  }
}

jason-fox avatar Jul 14 '22 11:07 jason-fox

Basically re-defining each attribute as:

attributes.push({
    type: 'Property',
    value,
    name,
    datasetId,
    metadata
 });

jason-fox avatar Jul 14 '22 11:07 jason-fox

I've done some investigations here and I've discovered something:

  • NGSI-v2 already partially supports metadata - I've added a test here: e7a7bb2
  • metadata support was missing from NGSI-v2 notifications - I've fixed it and added a test here: ca27860

So I don't think metadata is controversial.

datasetId is an NGSI-LD only thing, so there will be no need to add support to the NGSI-v2 handlers I guess. The datasetId attribute in each value can be left as undefined which conveniently enough aligns to the NGSI-LD concept of the default datasetId anyway, which is the 90% use case.

Once I've got notification based NGSI-LD commands extended as well, all that remains is to clearly document the difference in the docs stating that sending sequential commands to an endpoint is NGSI-LD only.

jason-fox avatar Jul 18 '22 07:07 jason-fox

Was this issue covered by PR https://github.com/telefonicaid/iotagent-node-lib/pull/1266?

  • Add: datasetId and metadata support for NGSI-LD PATCH+PUT operations (commands)

Or anything is pending?

fgalan avatar Aug 23 '22 10:08 fgalan

Still pending. At the moment the supportNulls flag discussed above is hardcoded. There should be also be a supportDatasetId flag too. supportMerge now exists (kind of) since the correct Unsupported Operation error response is returned if no mergeHandler has been set on the agent, and this aligns with the mechanism already in use with other handlers like queryHandler or commandHandler.

The docs should be updated to describe all these handlers, but they are already out of date since commandHandler and configurationHandler appear to be missing from the list, and not all signatures for the IoT Agent's library interface are listed correctly - not specifically a Merge-Patch issue in this case, just a lack of proper consistency in maintenance.

It doesn't help that there is no proper way of defining which bits of the existing interface actually are properly public and not going to change and which parts happen to be publicly accessible and are still subject to alteration or removal - this is due to the age of the codebase - a class based structure would do a better job of data hiding.

jason-fox avatar Aug 23 '22 11:08 jason-fox

The main part still missing is an ability to reject null and/or datasetId on purpose - i.e. "This IoT Agent can't understand that payload" - and make that configurable through config.js and environment variables.

jason-fox avatar Aug 23 '22 11:08 jason-fox

Completed.

jason-fox avatar May 12 '23 06:05 jason-fox