w3c / wot-thing-description

Web of Things (WoT) Thing Description
http://w3c.github.io/wot-thing-description/
Other
131 stars 63 forks source link

Allow for more TM fields to be optional #2042

Open JKRhb opened 3 months ago

JKRhb commented 3 months ago

In the context of https://github.com/w3c/wot-binding-templates/issues/258, one result of the discussion was that there might be cases where information within a Thing Model is primarily aimed at implementors of Things, indicating that they should support certain features or extensions of a protocol, like CoAP's Echo option. In this particular case, a consumer does not benefit that much from receiving this information in a TD, while implementors could use this information as a set of constraints for the Thing's behavior. However, at the moment it is required to take over all definitions (expect affordances labelled optional via tm:optional) into the resulting TD, which is why having vocabulary that is only used by Thing implementors is not really possible at the moment.

I was therefore wondering if we could either expand the scope of tm:optional to other levels of a TM or whether it could be possible to label vocabulary terms as optional during instantiation in general (e.g., in a Binding Template document where a vocabulary term is introduced). I guess the former approach would be a bit more flexible and would also cause less burden for specification authors, although it could make TMs a bit more verbose in certain scenarios.

When it comes to the example use case mentioned above, this could lead to the definition of a form like the following, where we use a JSON pointer to indicate that the cov:usesEcho member is optional via a tm:optional at the form level:

{
    "@context": [
      "https://www.w3.org/2022/wot/td/v1.1",
      {
        "cov": "http://www.example.org/coap-binding#"
      }
    ],
    "title": "ExampleThing",
    "securityDefinitions": {
        "nosec_sc": {"scheme": "nosec"}
    },
    "security": "nosec_sc",
    "properties": {
        "example": {
            "forms": [
              {
                "href": "coap://example.com/example",
                "cov:usesEcho": true, // Note: Only a placeholder
                "tm:optional": [
                  "/properties/status/forms/0/cov:usesEcho"
                ]
              }
           ]
        }
    }
}

Alternatively, we could also consider supporting JSON Path expressions, using the respective JSON object of the form as the root node. This would make the tm:optional array entry a bit more concise:

{
    "@context": [
      "https://www.w3.org/2022/wot/td/v1.1",
      {
        "cov": "http://www.example.org/coap-binding#"
      }
    ],
    "title": "ExampleThing",
    "securityDefinitions": {
        "nosec_sc": {"scheme": "nosec"}
    },
    "security": "nosec_sc",
    "properties": {
        "example": {
            "forms": [
              {
                "href": "coap://example.com/example",
                "cov:usesEcho": true, // Note: Only a placeholder
                "tm:optional": [
                  "$['cov:usesEcho']"
                ]
              }
           ]
        }
    }
}

Looking forward to your feedback on this – if this would make sense as a potential addition to the specification, then I would transform the content of this issue into a use case submission via the new template :)

JKRhb commented 2 months ago

As a simpler alternative to the proposals made above, you could probably also just use the keys of the object that contains the tm:optional (somewhat similar to the way tm:optional is handled for affordances) for labelling fields as optional:

{
    "@context": [
      "https://www.w3.org/2022/wot/td/v1.1",
      {
        "cov": "http://www.example.org/coap-binding#"
      }
    ],
    "title": "ExampleThing",
    "securityDefinitions": {
        "nosec_sc": {"scheme": "nosec"}
    },
    "security": "nosec_sc",
    "properties": {
        "example": {
            "forms": [
              {
                "href": "coap://example.com/example",
                "cov:usesEcho": true, // Note: Only a placeholder
                "tm:optional": [
                  "cov:usesEcho"
                ]
              }
           ]
        }
    }
}

Edit: Another alternative would be putting everything into the top-level tm:optional, like so:

{
    "@context": [
      "https://www.w3.org/2022/wot/td/v1.1",
      {
        "cov": "http://www.example.org/coap-binding#"
      }
    ],
    "title": "ExampleThing",
    "securityDefinitions": {
        "nosec_sc": {"scheme": "nosec"}
    },
    "security": "nosec_sc",
    "properties": {
        "example": {
            "forms": [
              {
                "href": "coap://example.com/example",
                "cov:usesEcho": true, // Note: Only a placeholder
              }
           ]
        }
    },
    "tm:optional": [
        "/properties/status/forms/0/cov:usesEcho"
    ]
}
egekorkan commented 1 month ago

This is definitely something that needs a use case, at least in my opinion. I do not use many TM-based workflows but I would like to get feedback from those who use tm:optional (maybe @thjaeckle). Do parsers really use tm:optional or is it purely interpreted by humans? Some other knowledge is needed to decided whether that optional affordance should be taken over not.

In this case, I feel that this is another use case. You are trying to provide implementation guidance. Shouldn't it be even a tm:remove since there is no point in carrying it over to the TD?

sebastiankb commented 1 month ago

I'm not 100% sure that I have understood the use case, especially the usesEcho example. So far, the tm:optional is used to express which interaction affordances do not necessarily have to be provided in a TD instance. Following this principle your example above would express that this kind of information "cov:usesEcho": true can be part in a TD instance or not. But you would rather use this information for the implementers, wouldn't you? I think, the tm:optional is not the perfect option for it.

I would be ok to have tm:optional on each key-value pair level to allow variety of TD instances. E.g., depending on the authorization, there is a TD instance version with complete details (e.g. for administrators) and instances with restricted information (e.g. for unauthorized users).

JKRhb commented 1 month ago

Thank you, @egekorkan and @sebastiankb, for your feedback on this :) I think you are right, @egekorkan, that this is actually a different use case than the one covered by tm:optional, for which cov:usesEcho was actually a bad example.

A better one could be something like cov:statusCode (as mentioned in https://github.com/w3c/wot-binding-templates/issues/258) that is (arguably) only relevant for implementers creating a TD producing application and could be removed during the TM's instantiation. Introducing something like tm:remove to indicate that would make sense to me. I guess the alternative could be mandating that a vocabulary term has to be removed during instantiation via the specification the term is defined, but that might be too inflexible and hard to keep track of.

I would be ok to have tm:optional on each key-value pair level to allow variety of TD instances. E.g., depending on the authorization, there is a TD instance version with complete details (e.g. for administrators) and instances with restricted information (e.g. for unauthorized users).

That also sounds good to me :) I guess the alternative could be creating separate Thing Models from a common parent here where only one is adding a certain field which can then be considered optional as well. But I think there might also be cases where you might want to optionally take over some information that is originally only intended for the TM and not important for the TD, like the model field in the instance object (although you could argue that this field should always be removed from the resulting TD).

thjaeckle commented 1 month ago

This is definitely something that needs a use case, at least in my opinion. I do not use many TM-based workflows but I would like to get feedback from those who use tm:optional (maybe @thjaeckle). Do parsers really use tm:optional or is it purely interpreted by humans? Some other knowledge is needed to decided whether that optional affordance should be taken over not.

Actually, Ditto also uses tm:optional in a maybe-not-so-intended way :D As you might remember, Ditto automatically generates and provides TDs for its "Things" (a.k.a digital twins), based on the linked ThingModel of a "Thing".
The generated TDs contain the actual HTTP endpoints for all modeled properties, actions, events, their data types, etc.

Another thing Ditto "uses" a referenced TM for is to create a Thing-JSON-Skeleton when creating a new "Thing" instance.
E.g. by simply doing a POST http://ditto.host/api/2/things with payload:

{
  "definition": "https://some.model.host/some-thing-model.tm.jsonld"
}

, Ditto will generate a JSON skeleton (maybe even hundreds of lines) with "default" values for the thing properties (either by defined default values from the TM or by the "neutral element" for the given data type).

In that case, Ditto will treat tm:optional for properties from a referenced ThingModel as properties which no default value will be generated for.

I am aware that this is not really intended, but it fits our use-case quite well without the need for another context extension.