Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Permit use of TD Links for Self-Description of Multiple Endpoints #269

Closed
wants to merge 8 commits into from
Closed

Permit use of TD Links for Self-Description of Multiple Endpoints #269

wants to merge 8 commits into from

Conversation

mmccool
Copy link
Contributor

@mmccool mmccool commented Jan 31, 2022

We have discussed using Thing Links for TDs returned by well-known URIs to support self-description by endpoints hosting multiple TDs. This PR adds the following:

  • An informative comment in the "well-known URI" section 5.2 discussing this use case
  • An informative comment in the "self-description" section 6.1 discussing this use case
  • An expanded definition of Thing Links to permit appropriate relation types
  • an updated architectural description and Figure 1 to show how Thing Links are expanded

Note: I may refactor the first two points since they have common content and put it instead in the opening section describing Introductions. Other Introduction mechanisms, i.e. Direct URL, also only result in one URL and can have similar problems.

Note 2: this description describes the current plan after discussion in the Discovery call on Jan 31; see comments below.


Preview | Diff

@mmccool
Copy link
Contributor Author

mmccool commented Jan 31, 2022

The current definition of "ThingLink" applies to the entire TD, but only has a "describedby" link type which is not really want we want. I would like to propose adding "thing" and "directory" types to links (to match the ones in CoreRD) so that a TD can be used, in essence, like an additional introduction mechanism.

@mmccool
Copy link
Contributor Author

mmccool commented Jan 31, 2022

Terminology updated to reference "Thing Links" (which are a type of TD) but we may want to have other link types than just "describedby".

@farshidtz
Copy link
Member

farshidtz commented Jan 31, 2022

IMO, the link relation should specify the relation. There is already a type field which specifies the media type application/td+json and can be extended with parameters if needed e.g. application/td+json;type=directory

For the DNS-SD service type, we default to Thing and allow setting directory:

type
Type of the Thing Description, i.e. Thing or Directory. If omitted, the type is assumed to be Thing.

@mmccool
Copy link
Contributor Author

mmccool commented Jan 31, 2022

I actually deleted my comment about Figure 4 before your comment as I noticed the subclass :). Anyway, let's discuss today.

@farshidtz
Copy link
Member

How about using hosts as suggested in #249 (comment)

hosts
Refers to a resource hosted by the server indicated by the link context.
This relation is used in CoRE where links are retrieved as a "/.well-known/core" resource representation, and is the default relation type in the CoRE Link Format.
https://www.iana.org/assignments/link-relations/link-relations.xhtml

See https://www.rfc-editor.org/rfc/rfc6690.html#section-7.2

@mmccool mmccool changed the title Permit use of TD Links in well-known URIs Permit use of TD Links for Self-Description of Multiple Endpoints Jan 31, 2022
@mmccool
Copy link
Contributor Author

mmccool commented Jan 31, 2022

Probably should up-level the comments under well-known URIs, they also apply to other introduction mechanisms, e.g. Direct URIs, QR codes, etc. It could also go into the (currently sadly empty) architectural introduction.

@mmccool
Copy link
Contributor Author

mmccool commented Jan 31, 2022

The IANA-defined relation type "item" is already mentioned in https://w3c.github.io/wot-thing-description/#link, and means "a TD that is a member of a collection" which is appropriate.

@mmccool
Copy link
Contributor Author

mmccool commented Jan 31, 2022

See also discussion in scripting on how to deal with composite TDs

@mmccool
Copy link
Contributor Author

mmccool commented Jan 31, 2022

Points to decide:

  • Expand Thing Link or add a new "type" of TDs?
    • Resolution: expand Thing Link
  • Do we use a different relation type than "describedby", and if so, what type?
    • The "item" implies a collection but there may not be a collection per se (it may only be a set of services that happen to be hosted on the same device but are otherwise unrelated).
    • The relation "hosts" is used in Core RD but is sort of generic, but may also be appropriate.
    • The type "thing" is used for Core RD to point at things (and there is also "directories", but "describedby" does cover that for directories referring to others).
    • Resolution: use either "hosts" or "external" for this relation. The first should be used when the target TD is under the same context IRI, and "external" when it is hosted elsewhere.
      • Note: does not replace "describedby". This is a different use case.
      • Note: both hosts and item assume the same "context IRI", so either is only appropriate for self-description where the TDs are, in fact, hosted on the same device. If you have to go somewhere else can use a "describedby" or better, an "external" link, however. We can allow "hosts" to be relative to the current TD, whereas "external" should be absolute.
  • Do we depend on the content type alone to resolve relation types?
    • Alone: no. In addition: redundant. Note: relation type is optional.
    • Resolution: use content type "application/td+json" only.
  • How do we handle Thing Link in the discovery process?
    • Resolution: follow links (and expand collections), and add them to the "bag" of TDs discovered
    • "collection" relationships are/should still described in the TDs themselves, so no information is lost)

@mmccool
Copy link
Contributor Author

mmccool commented Jan 31, 2022

I have expanded the definition of Thing Link to allow "hosts" and "external" relation types. This required a number of new assertions and a refactoring of existing ones. I also added an example and a use case distinguished from "describedby". Still to do: update the intro under "Architecture" and Figure 1 to show Thing Links and the "expansion" of Links. This section needed to be filled in anyway...

Copy link
Member

@farshidtz farshidtz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @mmccool. I think this is very clear. I just have some concerns about the paragraph about item and collection; please see the inline comment.

Comment on lines +661 to +663
If a set of Things <em>are</em> part of a collection, additional Links should be provided
in the individual TDs to describe such relations, for example using `collection` and
`item` relations.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this paragraph will add a lot of confusion because it directly overlaps with the functionalities of directories and other relation types defined above it. In this spec, we have numerous references to "collection", a JSON-LD class called "ThingCollection" and listing format "collection"; all referring to what is stored in the directory or the list of TDs.

Given that, can a Link with "collection" rel point to a directory? Because TD spec says: "collection: Points to a collections of Things". What will be the difference from a TD with type ThingDirectory and "describedby" link referring to that directory?

Looking at the RFC that defined that relation:

When included in a resource that represents a member of a collection,
the 'collection' link relation identifies a target resource that
represents a collection of which the context resource is a member.
https://www.rfc-editor.org/rfc/rfc6573.html#section-2.2

If I understand correctly, this means that the TD pointing to that link must be part of the linked "collection".

When included in a resource that represents a collection, the 'item'
link relation identifies a target resource that represents a member
of that collection.
https://www.rfc-editor.org/rfc/rfc6573.html#section-2.1

Is the linked "item" a member of that parent TD "collection"? Is the parent TD even a collection?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, I'll think about it. I could just take this out but I do want to emphasize that is this just an example. It's a lot easier to do the iterative discovery process if there is no important information stored in Thing Links, so they can be elided as part of the process. BTW I just expanded the arch intro to describe that process as well (including updating the diagram).

@relu91
Copy link
Member

relu91 commented Feb 1, 2022

Thank you for bringing this to the table and sorry for being absent in the latest Discovery calls. Some points:

Introducing the ability to point to a set of links in the ThingLink may solve the node-wot use case for read-only Thing Description Directory. So to expand a little bit the use case, node-wot is a servient runtime that is self-described by a Thing Description. Since the runtime may host one or more WebThings, the idea was to use the servient TD as an entry point to discover the list of WebThings hosted there. Now, reading the current proposal, I'm not sure if I have been allowed to mix Thing and ThingLink types in a TD. To be concrete here is the TD that I would like to host in node-wot:

{
   "title": "servient", 
   "id": "urn:dev:12321"
   "@type": ["Thing", "ThingLink"], 
   "links": [ {  
                    "rel": "hosts",
                    "href": "thing1",
                    "type": "application/td+json"
                 },
                 {
                   "rel": "hosts",
                   "href": "thing2",
                   "type": "application/td+json"
                 }],
   "actions" : {
      "shutdown": {},
      "setLogLevel": {},
      "runScript": {},
   }
}

Note: the assumption is that the servient TD is discovered using another introduction mechanism (e.g., DNS-SD).

Does this fulfill the requirements in this PR?

Another point: As you probably already know, with the newly introduced Thing Model Composition TDs may refer to their subparts using links with rel type item. I would harmonize that solution with what we are defining in this PR, which means that we should stick with the same rel type in both specs. Personally, I'm ok to use host instead of item so that we could discover TD subparts following the directions and the assertions given in the Discovery spec.

@mmccool
Copy link
Contributor Author

mmccool commented Feb 1, 2022

@relu91 Indeed, the use case I mentioned (multiple outlets on a power strip) could also be solved by having a single TD representing a "collection" with multiple components, each of which is itself a Thing, and connected by "item" Links. I think "hosts" is more appropriate for unrelated Things sharing a device. I'm need to talk to Ben to try and figure out the exact use case for that. Hubs is one, but it seems to be hubs should be powerful enough in general to run a Directory service. We could use "items" here, my concern is that I'd like to "flatten" Links during Discovery, so that Discovery just returns a flat set of TDs. If we use collection/item here I would be removing the "collection" master TD which is probably not desirable.

I was also thinking while writing this up that we should clarify whether you can mix "host" and "external" Links into a TD that also includes affordances. This seems odd to me and maybe an assertion disallowing it would be a good idea. I am also a bit troubled by the third use case for the "describedby" Thing Link, which implies subsetting a TD (and therefore allows mixing of affordances and Links). I think this is a bit odd but also relates to another general discussion about TD subsetting, and about when we can do it, etc. I personally don't think that use case (TD subsetting) belongs here and is a valid use case for Thing Links. I would prefer that Thing Links include NO affordances. That makes it a lot easier to reason about them and replace them with their referents during the Discovery process (now described under Architecture as part of this PR). If they have affordances, replacing them with their referents removes those affordances, which does not really fit that third use case. If we use "hosts" it can Link to both the "master" (collection) TD /and/ each "item" TD so the collection structure is maintained in the result of the Discovery.

@benfrancis
Copy link
Member

Does this just re-invent directories..?

@relu91 wrote:

To be concrete here is the TD that I would like to host in node-wot:

{
   "title": "servient", 
   "id": "urn:dev:12321"
   "@type": ["Thing", "ThingLink"], 
   "links": [ {  
                    "rel": "hosts",
                    "href": "thing1",
                    "type": "application/td+json"
                 },
                 {
                   "rel": "hosts",
                   "href": "thing2",
                   "type": "application/td+json"
                 }],
   "actions" : {
      "shutdown": {},
      "setLogLevel": {},
      "runScript": {},
   }
}

I really like this design for describing a collection of Things, and you will recall that it was one of the proposals for describing a Directory. But the conclusion at the time was that a Thing Description should be considered to be fairly static resource, so providing a dynamic list of links inside a Thing Description wasn't a good idea.

The current discovery process is farily simple

  1. The Introduction mechanism results in a URL
  2. That URL can either resolve to a Thing Description (describing a single Thing) or a Directory Description (providing access to a collection of Things)

As far as I can tell this PR adds an additional mechanism for describing a collection of devices in addition to a Directory. Now that URL from the introduction mechanism could resolve to:

  1. A Thing Description
  2. A Directory Description
  3. A ThingLink linking to a single Thing
  4. A ThingLink linking to multiple Things

This adds quite a lot of implementation complexity for Consumers and doesn't actually solve the original problem which I think may have triggered this issue which related to the well-known URI introduction mechanism.

The problem (identified in w3c/wot-profile#121 (comment)) is simply that if the well-known URI mechanism is made mandatory for the Core Profile then that has the side-effect of also making support for the Directory Service API mandatory for conformant Consumers, since if a well-known URI may resolve to a Directory Description then a Consumer will need to know what to do with it.

Extending the well-known URI introduction mechanism so that it may also resolve to a ThingLink linking to a single Thing or a ThingLink linking to multiple Things doesn't solve that problem, it just adds further implementation complexity.

Two ways of solving that problem are:

  1. Simply not making the well-known URI introduction mechanism mandatory in the Core Profile (which is my recommendation)
  2. Making support for the Directory Service API mandatory in the Core Profile (which I'm also fine with, but which adds implementation complexity for Consumers, so it might make sense for it to be part of a separate profile instead)

I may have misunderstood and you're actually trying to solve another problem, but I think this PR just adds a duplicate mechanism for describing collections of Things.

The issue of read-only directories should be probably be treated separately in #208 and is really just a case of making write operations optional in the spec.

@relu91
Copy link
Member

relu91 commented Feb 1, 2022

If we use collection/item here I would be removing the "collection" master TD which is probably not desirable.

But in principle, you can still recover it using the backlink contained in the collection items, right? Also, why remove the master collection TD?

I would prefer that Thing Links include NO affordances. That makes it a lot easier to reason about them and replace them with their referents during the Discovery process (now described under Architecture as part of this PR). If they have affordances, replacing them with their referents removes those affordances, which does not really fit that third use case. If we use "hosts" it can Link to both the "master" (collection) TD /and/ each "item" TD so the collection structure is maintained in the result of the Discovery.

It is a little bit annoying to be presented with just an empty TD that refers to the "master" collection and its items (you need an additional fetch), but I understand your previous concerns.

Does this just re-invent directories..?

TBH, it kinda is. Indeed, in my mind, it covers the same use case (node-wot needs to present its WebThings). However, I know that the intention here is to have a simplified solution for small devices that hosts multiple WebThings. Therefore, in such use cases, the number of hosted WebThings will be quasi-static and they can be presented as links in a static TD document.

The problem (identified in w3c/wot-profile#121 (comment)) is simply that if the well-known URI mechanism is made mandatory for the Core Profile then that has the side-effect of also making support for the Directory Service API mandatory for conformant Consumers, since if a well-known URI may resolve to a Directory Description then a Consumer will need to know what to do with it.

I actually missed that discussion, but as I said above I think we have other valid use-cases.

The issue of read-only directories should be probably be treated separately in #208 and is really just a case of making write operations optional in the spec.

Ok, point taken. I just want to mention that if read-only TDDs will be implemented then the node-wot use case is covered. Basically, the runtime will expose the following TD:

{
   "title": "servient", 
   "id": "urn:dev:12321"
   "@type": ["Thing", "ThingDirectory"], 
   "properties": {
      "things": {},
    }
   "actions" : {
      "shutdown": {},
      "setLogLevel": {},
      "runScript": {},
   }
}

@benfrancis
Copy link
Member

@relu91 wrote:

I just want to mention that if read-only TDDs will be implemented then the node-wot use case is covered. Basically, the runtime will expose the following TD:

{
   "title": "servient", 
   "id": "urn:dev:12321"
   "@type": ["Thing", "ThingDirectory"], 
   "properties": {
      "things": {},
    }
   "actions" : {
      "shutdown": {},
      "setLogLevel": {},
      "runScript": {},
   }
}

This is exactly what we need for WebThings Gateway too. A Thing Description which can describe the physical gateway itself as a Thing (with actions like "reboot"), but also the list of Things it hosts (via the things property). I would have liked that to be a list of links rather than a property, but that's not the solution that was landed on for directories.

I do agree that a directory is overkill for the "multiple outlets on a power strip" use case, but I'm not sure they're actually multiple Things. I would personally model that as one Thing, but it could also be modelled as a top level Thing (with its own Thing Description) which links to other sub-Things.

@mmccool
Copy link
Contributor Author

mmccool commented Feb 2, 2022

General comments, we can discuss more in the upcoming profile mtg:

  • the Thing Link approach is specifically for the use case of one small device hosting a small number of static Things, and for when you want to support self-discovery. If you want to support a dynamic set of Things, then you really need an API to manage the set, notifications of updates, etc; that's the use case for the TDD service. Please don't use the Thing Link approach for dynamic resources, that's not its use case (I think I said that somewhere in the text, also...).
  • I think it would be fine in Profiles to disallow directories in some cases. However, the architecture means that the Thing can decide whether it wants to host a TDD service or not. It's not forced to; if it is, please point out specifically what we would have to change in the spec.
  • I bring up the power bar example because I ran into this aggravating issue when trying to deal with automations in Home Assistant and Smart Things. Basically lots of automation rules assume that they are dealing with "singular" items, i.e. one on-off switch, one sensor value. They get confused by devices that have multiple actuators or sensor values. So rather than have one big Thing with a lot of affordances in this case that you then have to index into, it's better to have a bunch of simpler Things that you can reference directly imo. Simply less chance of other parts of the system getting confused. As noted, "collection/item" can also do this. However using "hosts" means that the discovery process itself can "flatten" the set so the automation system would just see a bunch of devices.
  • Which gets to the last point, mixing in affordances into the Thing Link. I would prefer not to do this as I'd like the option to allow the Discovery process to "expand" Thing Links by replacing them with their referents. If you want to provide "host control" affordances then create one and add it to the set of links.

@benfrancis
Copy link
Member

Thanks for these clarifications @mmccool. I doubt we'll have time to discuss this in the WoT Profile meeting today, so I'll leave a couple of follow-up comments below.

  • the Think Link approach is specifically for the use case of one small device hosting a small number of static Things, and for when you want to support self-discovery. If you want to support a dynamic set of Things, then you really need an API to manage the set, notifications of updates, etc; that's the use case for the TDD service. Please don't use the Thing Link approach for dynamic resources, that's not its use case (I think I said that somewhere in the text, also...).

OK, that makes sense.

  • I think it would be fine in Profiles to disallow directories in some cases. However, the architecture means that the Thing can decide whether it wants to host a TDD service or not. It's not forced to; if it is, please point out specifically what we would have to change in the spec.

The issue is not about what Things can do, but what Consumers must support. The point of a profile is to guarantee out-of-the-box interoperability between conformant Things and Consumers. This means that any feature which is optional for Things must necessarily be mandatory for Consumers. In other words, if Things can choose to host a Thing Directory then all Consumers must support Thing Directories. We could work around the problem by monkey-patching the WoT Discovery specification in the WoT Profile specification, defining that support for the well-known URI discovery mechanism is mandatory but excluding the Directory Description part. But it would be much cleaner if we could just reference introduction & exploration mechanisms directly.

Extending the well-known URI mechanism to support two different types of ThingLinks would mean that if the well-known URI mechanism was mandatory for the Core Profile, those features would have to be mandatory for all conformant Consumers too, which further adds to the problem.

Which gets to the last point, mixing in affordances into the Thing Link.

What we were suggesting was not adding affordances into a Thing Link, but using a Thing Description instead.

I'm not saying that you shouldn't extend the well-known URI mechanism*, only that doing so makes it even less feasible for it to be part of the Core Profile.


*I'm still not completely convinced by the necessity of ThingLinks at all, but that's a separate matter.

Copy link
Member

@farshidtz farshidtz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR is a bit drifting apart from the use case, which was about the limitation that well-known URLs don't allow setting base baths, making it impossible to expose multiple TDs from a single domain. See #249

I now also think there is indeed a bit of overlap with the directory, in particular for the "external" relation. If the TD is external, it can probably self-describe itself using a separate well-known address. Or do we have another use case for this?
If one or more TDs are related to each other, then another link relation can be chosen to define the nature of that relation.

Back to the original well-known issue and away from my initial standpoint: maybe it is better to allow returning a single TD or an array of TDs from well-known and leave Thing Link alone?

Comment on lines +721 to +732
In some cases a single URL may need to return multiple
TDs. For large numbers of TDs that may need to change
dynamically over time,
a <a>Thing Description Directory</a> (TDD)
can be used instead; in such a case the TD returned is that
of the TDD.
If a small fixed number of TDs need to be returned,
particularly on small devices that do not want to host the
full TDD interface, a single TD can be returned, marked as
a Thing Link, which link to multiple TDs hosted
at different
URLs.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This gives the false impression that Thing Link and TDD are alternative ways of returning multiple TDs. But in fact, Thing Link serves the very specific purpose of allowing a single TD to reference one or more.

</mxGraphModel>
</diagram>
</mxfile>
Copy link
Member

@farshidtz farshidtz Feb 2, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

images/overview.png

This figure is confusing:

  1. The diagram makes it look like Thing Link and TD are different entities. Thing Link is a type of TD.
  2. Exploration enclosure is covering only directory. Instead it should cover everything after URL is found. Note: "These URLs do not themselves contain metadata, but are used in the second stage, "Exploration", to actually fetch metadata."

I'd instead point from URL to TD (self-described Thing) and use empty arrow heads to divide it using from there into Thing Directory (pointing back to TD) and Thing Link (pointing back to URL).

@mmccool
Copy link
Contributor Author

mmccool commented Feb 7, 2022

Re-read everything, collecting some observations here for discussion...

  • Ben's concern was about complicating the consumer since .well-known might point at a Directory. But ANY introduction can point at a Directory.
  • It seems in general that the discovery process is for the consumer (as opposed to the server) is not very well described... and really probably needs some normative content... impacting our schedule...
  • Indeed, adding Thing Links further complicates the consumer. I still think the issue is valid, but the current proposal is pretty complicated and requires multiple accesses. Just returning an array of TDs from .well-known would be FINE in my opinion. It does not handle "external" but I think that's OK: .well-known is for self-description anyway.

@mmccool mmccool mentioned this pull request Feb 7, 2022
@mmccool
Copy link
Contributor Author

mmccool commented Feb 7, 2022

See comments on #208 for our resolution to this. The conclusion was that rather than adding another mechanism for "simple" directories, we should make directories themselves easier to implement and use in simple cases. So we are going to clean up the spec to make only "listing" mandatory (and registration optional). Also, Issue #272 has been added to address the fact that we need to better describe what is expected of a consumer supporting discovery (e.g. they should be able to deal with at least the "listing" affordance of a directory).

@mmccool
Copy link
Contributor Author

mmccool commented Feb 7, 2022

We decided against the "just have .well-known return an array of TDs" as it breaks the invariant we decided upon: Introduction mechanisms MUST always return (one or more) URLs that each point at a (single) TD. (Hmm... not sure that is an assertion anywhere. It should be, will check).
Note that Intros are in general allowed to return multiple URLs (DID and DNS-SD being examples) but .well-known can't, which is the root of the issue here.

@mmccool
Copy link
Contributor Author

mmccool commented Feb 7, 2022

Some of the comments above relate to improvements to Figure 1 to make it clearer. I'll see if I can address these as part of the resolution of Issue #272

@mmccool mmccool mentioned this pull request Feb 13, 2022
7 tasks
@mmccool
Copy link
Contributor Author

mmccool commented Feb 14, 2022

The discussion above is relevant, but the particular solution is not ideal, so we are going to take a different tack (making simple read-only directories simple) and adding more detail on client requirements. So I am going to close this without merging. Some of the content, however, has been moved to other PRs...

@mmccool mmccool closed this Feb 14, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants