-
Notifications
You must be signed in to change notification settings - Fork 17
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
Refactoring TDD Thing Description #133
Comments
There is a PR to discuss and add this: #130 In your proposal, why retrieving all TDs is still a property but retrieving one TD is an action? Regarding |
Thank you for linking the PR. I think we could go ahead with that because it is consistent with the previous assumptions. Then maybe if we reach a consensus here do a simple refactor.
I see that it might have been confusing introducing that property, but let me try to explain. My rationale was that the Thing Description Directory contains a list or a collection of TDs. In principle obtaining this list would not require any logical processing: just take the list and return it. On the other hand, retrieving a single TD requires, again logically, scanning through the list and Anyhow, I could live with having a retriveAllTD as an action. I would focus on the refactor itself rather than this detail.
Thanks for the clarification. I am aware of the reasons behind that design choice in this TD, but as I pointed in the post above (I know it's not a short comment 🤣 and it might need improvements) I commented here why we might think again about their roles in actions. |
@relu91 wrote:
Is there going to be a version of the Directory Service API which isn't a REST API? My understanding from the current draft was that this was a concrete prescriptive API which always uses HTTP, not an abstract API which would have multiple bindings. I do think it's challenging to describe this API using a Thing Description because TDs don't deal well with collections of resources. But FWIW my understanding of actions is that they do always cause a change in state. The wording used in Mozilla's draft specification (which incidentally also defines an API for listing things but not described by a TD), was:
In a REST API reading, listing and searching resources maps well onto GET requests since they are operations which do not cause a change in state and are idempotent. I would expect these types of operations to map onto properties, not actions. |
I sensed during different calls that the direction was "let's start from HTTP than we can later move on with other protocol bindings", but I might be wrong. I think @farshidtz is more aligned with your statement. However, I would like to underline that if we follow an abstract designing moving to other protocols would be free. Which are the benefits of pursuing the current design? I'd like to quote @k-toumura (complete comment) :
Not sure if I am following, but the definition that you quoted says that an Action can also be used as a function that has a different outcome based on the provided arguments (i.e., a filter). Also, the current definition in WoT Architecture does not mandate that an Action Affordance MUST/SHOULD always change the state or using it, as quoted in the first post it now uses MAY. I have some doubts, don't you think that calling a Property with a verb is strange? (e.g., retrieve, searchJSON) I think it hints at some bad design... What does stop us to use a GET operation in Action? |
@relu91 wrote:
That is true. But the directory API is a bit of a strange example because it's not actually a device with physical properties, the TD is (somewhat awkwardly) being used to describe an HTTP REST API of a software web service describing a collection of resources (more like OpenAPI).
Yes, where the "outcome" is a change in state.
That is true, and I agree with the comments in w3c/wot-thing-description#1020 that the use of properties vs. actions is poorly defined in the current TD specification.
Yes that's another matter and I agree. But https://google.com/search?q=foo with a GET request is a very common pattern for searching on the web and...
If we agree that actions always change state, then a GET request is not appropriate because GET requests should never change state and should be idempotent. But it seems that's a separate debate. I'm planning on doing an in-depth review of the discovery specification today so will get back to you with further comments. |
BTW we could have a more REST-oriented description using OpenAPI and a TD at the same time. In my understanding having a well-defined TD (which should be more a TM but we still don't have a stable description for that) is that consumers who already have the WoT stack would find more natural to interact with a TDD described by a TD (i.e., use the same libraries and utilities as if they were interacting with another WebThing). |
We currently describe the HTTP API but don't say that HTTP should be the only protocol.
Is the name of an interaction really the basis to choose the interaction type? If so, changing "retrieveTD" to "TD" solved that problem! We should choose based on the interaction specifications. Every operation needs processing, only some change the state. Some operations always have input and output (e.g. SPARQL search with POST method) and could be modeled better as actions. But properties may also have different input and outputs schemas (see w3c/wot-thing-description#1053). Since the updated specification allows the use of action for an interaction that doesn't change the state, I have no problem using actions for ALL RESTful interactions on the TDD.
See #82 |
Well since a TD is not read only by machines but also humans naming is important as it conveys purpose and meaning. About renaming again it is about the meaning, retrievedTD is Action whereas TDs is a Property.
Totally agree that we should follow the spec and I think we are on the same page then! |
OK, having read the specification in more depth I have an alternative proposal to simplify the Directory Service API and its Thing Description. This includes:
(See additional notes at the end). {
"@context": [
"https://www.w3.org/2019/wot/td/v1",
"https://www.w3.org/2021/wot/tdd/v1"
],
"@type": "Directory",
"title": "My Directory",
"properties": {
"things": {
"@type": "ThingListProperty",
"title": "Things",
"description": "The collection of things the directory serves",
"forms": [
{
"href": "/things/",
"htv:methodName": "GET",
"contentType": "application/json"
},
{
"href": "/things/{id}",
"htv:methodName": "GET",
"contentType": "application/json"
},
{
"href": "/things/?jq={jq}",
"htv:methodName": "GET",
"contentType": "application/json"
},
{
"href": "/things/?xq={xq}",
"htv:methodName": "GET",
"contentType": "application/json"
},
{
"href": "/things/?sq={sq}",
"htv:methodName": "GET",
"contentType": "application/json"
}
],
"uriVariables": {
"id": {
"@type": "ThingID",
"title": "Thing Description ID",
"type": "string",
"format": "uri"
},
"jq": {
"@type": "JSONPathQuery",
"type": "string",
"title": "JSON Path search query"
},
"xq": {
"@type": "XPathQuery",
"type": "string",
"title": "XPath search query"
},
"sq": {
"@type": "SPARQLQuery",
"type": "string",
"title": "SPARQL search query"
}
}
}
},
"actions": {
"createThing": {
"@type": "CreateThingAction",
"forms": [
{
"href": "/things/",
"htv:methodName": "POST",
"contentType": "application/td+json"
},
{
"href": "/things/{id}",
"htv:methodName": "PUT",
"contentType": "application/td+json"
},
],
"uriVariables": {
"id": {
"@type": "ThingID",
"title": "Thing Description ID",
"type": "string",
"format": "uri"
}
},
"input": {
"@type": "Thing",
"type": "object",
},
},
"updateThing": {
"@type": "UpdateThingAction",
"forms": [
{
"href": "/things/{id}",
"htv:methodName": "PUT",
"contentType": "application/td+json"
},
{
"href": "/things/{id}",
"htv:methodName": "PATCH",
"contentType": "application/td+json"
}
],
"uriVariables": {
"id": {
"@type": "ThingID",
"title": "Thing Description ID",
"type": "string",
"format": "uri"
}
},
"input": {
"@type": "Thing",
"type": "object",
},
},
"deleteThing": {
"@type": "DeleteThingAction",
"forms": [{
"href": "/things/{id}",
"htv:methodName": "DELETE",
}],
"uriVariables": {
"id": {
"@type": "ThingID",
"title": "Thing Description ID",
"type": "string",
"format": "uri"
}
},
}
},
"events": {
"thingCreated": {
"@type": "ThingCreatedEvent",
"data": {
"type": "object"
},
"forms": [{
"href": "/events/thingCreated",
"contentType": "application/json"
}],
},
"thingUpdated": {
"@type:": "ThingUpdatedEvent",
"data": {
"type": "object"
},
"forms": [{
"href": "/events/thingUpdated",
"contentType": "application/json"
}],
},
"thingDeleted": {
"@type": "ThingDeletedEvent",
"data": {
"type": "object"
},
"forms": [{
"href": "/events/thingDeleted",
"contentType": "application/json"
}],
}
}
} Notes:
|
@relu91: Could you live with the above? The property is a noun and the actions are verbs and it's compliant with the description of properties vs. actions in the TD spec (though I expect the debate will continue in w3c/wot-thing-description#1020). The query parameters on the GET requests are really just to filter the response. |
Thank you for researching and providing a concrete full refactoring of the TD. Your proposal seems reasonable and well designed, what I like is the rationale that you put in your first 4 notes:
+1 especially for point 4. So yeah it is an improvement that I would approve 👍 . What concern me is: how I client can choose the right form to issue query the TDD? I think the TD spec misses to explain how to select a form using the Aside from that, sorry for stressing this again, but what is wrong with this TD? {
"@context": [
"https://www.w3.org/2019/wot/td/v1",
"https://www.w3.org/2021/wot/tdd/v1"
],
"@type": "Directory",
"title": "My Directory",
"properties": {
"things": {
"@type": "ThingListProperty",
"title": "Things",
"description": "The collection of things the directory serves",
"forms": [
{
"href": "/things/",
"htv:methodName": "GET",
"contentType": "application/json"
}
]
}
},
"actions": {
"search": {
"@type": "SearchThingsAction",
"title": "search",
"description": "Search among the list of Thing Descriptions",
"forms":[
{
"href": "/things/{id}",
"htv:methodName": "GET",
"contentType": "application/json"
},
{
"href": "/things/?jq={jq}",
"htv:methodName": "GET",
"contentType": "application/json"
},
{
"href": "/things/?xq={xq}",
"htv:methodName": "GET",
"contentType": "application/json"
},
{
"href": "/things/?sq={sq}",
"htv:methodName": "GET",
"contentType": "application/json"
}
],
"uriVariables": {
"id": {
"title": "Thing Description ID",
"type": "string",
"format": "uri"
},
"jq": {
"@type": "JSONPathQuery",
"type": "string",
"title": "JSON Path search query"
},
"xq": {
"@type": "XPathQuery",
"type": "string",
"title": "XPath search query"
},
"sq": {
"@type": "SPARQLQuery",
"type": "string",
"title": "SPARQL search query"
}
}
}
/*Same fields of above*/
}
} Notice, we still have the how to select the right form problem. A simple workaround here (which is not possible modeling search operations as filters of the property {
"@context": [
"https://www.w3.org/2019/wot/td/v1",
"https://www.w3.org/2021/wot/tdd/v1"
],
"@type": "Directory",
"title": "My Directory",
"properties": {
"things": {
"@type": "ThingListProperty",
"title": "Things",
"description": "The collection of things the directory serves",
"forms": [
{
"href": "/things/",
"htv:methodName": "GET",
"contentType": "application/json"
}
]
}
},
"actions": {
"find":{
"@type": "FindTDAction",
"title": "search",
"description": "Search among the list of Thing Descriptions",
"forms": [
{
"href": "/things/{id}",
"htv:methodName": "GET",
"contentType": "application/json"
}
]
},
"searchJsonPath":{
"@type": "SearchJsonPathThingsAction",
"title": "Search using JSON Path",
"description": "Query the list of Thing Descriptions using JSON Path",
"forms":[{
"href": "/things/?jq={jq}",
"htv:methodName": "GET",
"contentType": "application/json"
}]
}
/*etc. */
}
} As a bonus feature detection for nonsematic consumers would be simply |
I agree this isn't clear from the WoT Thing Description specification and would need specifying in the WoT Discovery specification. But what exactly should be standardised? The names of interaction affordances and variable names of My suggestion would be to standardize a capability schema for a directory with:
This allows all the names of interaction affordances, URIs and URI variables to be chosen by the developer, but should give consumers enough hints about how to consume the API.
Yes, that might be useful too. The only other tool I can think of which might be useful here is adding a new set of
Only that it breaks the rule that actions should only be used to modify state (and only where setting a property alone is not sufficient). That debate really needs resolving in w3c/wot-thing-description#1020
Yes, though that only really works if search operations are actions (see above) and makes for a messier TD in my opinion. |
I've provided an example of this below, which works quite well for properties and actions, but as you can see doesn't provide enough information on its own for a client to know how to to carry out all operations (e.g. distinguishing between different types of {
"@context": [
"https://www.w3.org/2019/wot/td/v1",
"https://www.w3.org/2021/wot/tdd/v1"
],
"@type": "Directory",
"title": "My Directory",
"properties": {
"things": {
"@type": "ThingListProperty",
"title": "Things",
"description": "The collection of things the directory serves",
"forms": [
{
"op": "readallthings",
"href": "/things/",
"htv:methodName": "GET",
"contentType": "application/json"
},
{
"op": "readthing",
"href": "/things/{id}",
"htv:methodName": "GET",
"contentType": "application/json"
},
{
"op": "readmultiplethings",
"href": "/things/?jq={jq}",
"htv:methodName": "GET",
"contentType": "application/json"
},
{
"op": "readmultiplethings",
"href": "/things/?xq={xq}",
"htv:methodName": "GET",
"contentType": "application/json"
},
{
"op": "readmultiplethings",
"href": "/things/?sq={sq}",
"htv:methodName": "GET",
"contentType": "application/json"
}
],
"uriVariables": {
"id": {
"@type": "ThingID",
"title": "Thing Description ID",
"type": "string",
"format": "uri"
},
"jq": {
"@type": "JSONPathQuery",
"type": "string",
"title": "JSON Path search query"
},
"xq": {
"@type": "XPathQuery",
"type": "string",
"title": "XPath search query"
},
"sq": {
"@type": "SPARQLQuery",
"type": "string",
"title": "SPARQL search query"
}
}
}
},
"actions": {
"createThing": {
"@type": "CreateThingAction",
"forms": [
{
"op": "creatething",
"href": "/things/",
"htv:methodName": "POST",
"contentType": "application/td+json"
},
{
"op": "creatething",
"href": "/things/{id}",
"htv:methodName": "PUT",
"contentType": "application/td+json"
},
],
"uriVariables": {
"id": {
"@type": "ThingID",
"title": "Thing Description ID",
"type": "string",
"format": "uri"
}
},
"input": {
"@type": "Thing",
"type": "object",
},
},
"updateThing": {
"@type": "UpdateThingAction",
"forms": [
{
"op": "updatething",
"href": "/things/{id}",
"htv:methodName": "PUT",
"contentType": "application/td+json"
},
{
"op": "updatething",
"href": "/things/{id}",
"htv:methodName": "PATCH",
"contentType": "application/td+json"
}
],
"uriVariables": {
"id": {
"@type": "ThingID",
"title": "Thing Description ID",
"type": "string",
"format": "uri"
}
},
"input": {
"@type": "Thing",
"type": "object",
},
},
"deleteThing": {
"@type": "DeleteThingAction",
"forms": [{
"op": "deletething",
"href": "/things/{id}",
"htv:methodName": "DELETE",
}],
"uriVariables": {
"id": {
"@type": "ThingID",
"title": "Thing Description ID",
"type": "string",
"format": "uri"
}
},
}
},
"events": {
"thingCreated": {
"@type": "ThingCreatedEvent",
"data": {
"type": "object"
},
"forms": [{
"href": "/events/thingCreated",
"contentType": "application/json"
}],
},
"thingUpdated": {
"@type:": "ThingUpdatedEvent",
"data": {
"type": "object"
},
"forms": [{
"href": "/events/thingUpdated",
"contentType": "application/json"
}],
},
"thingDeleted": {
"@type": "ThingDeletedEvent",
"data": {
"type": "object"
},
"forms": [{
"href": "/events/thingDeleted",
"contentType": "application/json"
}],
}
}
} |
Just want to say that even if we enforce the whole TD / Thing Model, it might be beneficial to specify semantic types as you are suggesting.
that's right, even if I am not really sure about the current definition of Action:
To me, it just says that everything is optional (it's all a big MAY) and the only thing that is stated is that it is something to invoke a function, but I agree let's move the discussion onto w3c/wot-thing-description#1020. Not sure about the new operation types, they would add quite a complexity to the protocol binding implementation. I would prefer to resolve the debate on actions/properties and spawn different affordances. Anyhow, given the current spec, I think we reached a good proposal here, which is an improvement with the current solution. |
@farshidtz What do you think of the proposal in #133 (comment) ? I am happy to create a PR if it helps. |
My comments will be based on the current TD available here. Some general comments:
The events were merged into one form to allow subscription to one, multiple, or all events. Also, other query arguments for subscribing to a particular TD or toggling differences are missing. We could try to simplify current data schema by reducing to a single schema for all types.
The first context URI is the current URI used in TD 1.1. The second context URI is intentionally set to the draft URL. The URL should be a valid one, pointing to the context file to allow resolution of the type from
I think those are important to consumers. The TD should be complete if we don't want to provide any OpenAPI spec.
The clients should already be authenticated in order to access the Directory Description (if not public). The security metadata is meant for accessing the interactions. |
@farshidtz thank you for your detailed reply!
Why does a description of a thing have a
OK, the ones in the draft you linked to make sense.
I agree tds/TDS/TDs are not great choices. As you say, the Thing Description specification already refers to a Thing Description as a "Thing". (As far as the Web of Things is concerned, the Thing Description resource is the thing, or at least its top level resource, like an index.html). I don't see any confusion in the idea that a The important point is that there's a single resource which represents a list of things, which can be filtered in different ways.
That's really a separate issue.
I see. Fortunately it is still possible to differentiate between a POST to create a thing and a POST to query things using
With the above distinction, I think search can be combined too. Note that "search" is not a good name for a property because it is a verb (the same applies to "retrieveTD"), property names should really be nouns.
I agree.
I agree, though obviously "readable" and "simple" is subjective, hence my suggestion of more flexibility for developers (#144).
This feels really strange, because you could make the same argument for any Thing Description. Should all Thing Descriptions only define a single event? I think this is an argument for a
OK, makes sense.
OK, fair enough.
Let's continue to discuss this in #135. Other questions:
I have drafted an updated proposed TD based on the one you linked to. It's very large though so at this point it might be easier to discuss the finer points in a pull request. What branch should I send a pull request to? Thanks.
|
DirectoryDescription and LinkDescription were added together. See #54. Please raise your concerns in #43 and discuss it with the semantics members (you can mention AndreaCimminoArriaga). Keep in mind that DirectoryDescription is an alias; you can set it to anything you want and map it to discovery:DirectoryDescription in context.
This is a reasonable approach, keeping
This is about a directory, serving a large number of clients. Separating the events forces each client who wants all events to maintain three persistent connections with the server. This is fine in HTTP/2 because these connections gets multiplexed on a single socket. But clients still need to subscribe three times. With that said, I don't have have a strong objection against separating them. We should discuss this further though, so let's try to do an incremental refactoring.
The server should have the means to check this internally, e.g. by checking if it already exists or checking the DB response.
You should ask this on the TD issue tracker. TD IDs are IRIs as far as the JSON Schema states.
It doesn't have to be. It is recommended. From the spec: "The identifier SHOULD be a Version 4 UUID URN [RFC4122]."
It is from SSE; please read https://w3c.github.io/wot-discovery/#exploration-directory-api-notification Some minor things about the TD: I think jsonpath and xpath are better than jquery (jQuery?) and xquery. Also, without the trailing slash is between /things and ?. |
On a second thought, while that is is technically valid in HTTP, it has some problems:
One alternative would be to just decouple sparql's POST endpoint and leave the rest on
|
We might need to test this, but presumably if there was a
Agreed, both JQuery and XQuery have other meanings so would be confusing.
It's not as neat, but I agree the Although I'm not an expert in any of these technologies, it does make some sense in my head to handle JSONPath and XPath separately from SPARQL given that the former two provide expressions to select nodes from the JSON tree, whereas SPARQL is more of a fully fledged database query language like SQL and XQuery (which builds on XPath). Others may see the distinction differently though. I'm therefore not sure whether the Updated TD below. I'll try to split this into multiple pull requests to review when I get the chance. {
"@context": [
"http://www.w3.org/ns/td",
"https://w3c.github.io/wot-discovery/context/discovery-context.jsonld"
],
"@type": "Directory",
"title": "Example Thing Description Directory (TDD)",
"version": {
"instance": "1.0.0-alpha"
},
"securityDefinitions": {
"oauth2_code": {
"scheme": "oauth2",
"flow": "code",
"authorization": "https://auth.example.com/authorization",
"token": "https://auth.example.com/token",
"scopes": [
"write",
"read",
"search"
]
},
"oauth2_client": {
"scheme": "oauth2",
"flow": "client",
"token": "https://auth.example.com/token",
"scopes": [
"write",
"read",
"search"
]
},
"oauth2_device": {
"scheme": "oauth2",
"flow": "device",
"authorization": "https://auth.example.com/device_authorization",
"token": "https://auth.example.com/token",
"scopes": [
"write",
"read",
"search"
]
},
"combo_sc": {
"scheme": "combo",
"oneOf": [
"oauth2_code",
"oauth2_client",
"oauth2_device"
]
}
},
"security": "combo_sc",
"base": "https://tdd.example.com",
"actions": {
"createThing": {
"@type": "CreateThingAction",
"description": "Create a Thing Description",
"uriVariables": {
"id": {
"@type": "ThingID",
"title": "Thing Description ID",
"type": "string",
"format": "iri-reference"
}
},
"forms": [
{
"href": "/things/{id}",
"htv:methodName": "PUT",
"contentType": "application/td+json",
"response": {
"description": "Success response",
"htv:statusCodeValue": 201
},
"additionalResponses": [
{
"description": "Invalid serialization or TD",
"contentType": "application/problem+json",
"htv:statusCodeValue": 400
}
],
"scopes": "write"
},
{
"href": "/things",
"htv:methodName": "POST",
"contentType": "application/td+json",
"response": {
"description": "Success response",
"htv:headers": [
{
"description": "System-generated URI",
"htv:fieldName": "Location",
"htv:fieldValue": ""
}
],
"htv:statusCodeValue": 201
},
"additionalResponses": [
{
"description": "Invalid serialization or TD",
"contentType": "application/problem+json",
"htv:statusCodeValue": 400
}
],
"scopes": "write"
}
]
},
"updateThing": {
"description": "Update a Thing Description",
"uriVariables": {
"id": {
"@type": "ThingID",
"title": "Thing Description ID",
"type": "string",
"format": "iri-reference"
}
},
"forms": [
{
"href": "/things/{id}",
"htv:methodName": "PUT",
"contentType": "application/td+json",
"response": {
"description": "Success response",
"htv:statusCodeValue": 204
},
"additionalResponses": [
{
"description": "Invalid serialization or TD",
"contentType": "application/problem+json",
"htv:statusCodeValue": 400
}
],
"scopes": "write"
},
{
"href": "/things/{id}",
"htv:methodName": "PATCH",
"contentType": "application/merge-patch+json",
"response": {
"description": "Success response",
"htv:statusCodeValue": 204
},
"additionalResponses": [
{
"description": "Invalid serialization or TD",
"contentType": "application/problem+json",
"htv:statusCodeValue": 400
},
{
"description": "TD with the given id not found",
"contentType": "application/problem+json",
"htv:statusCodeValue": 404
}
],
"scopes": "write"
}
]
},
"deleteThing": {
"description": "Delete a Thing Description",
"uriVariables": {
"id": {
"@type": "ThingID",
"title": "Thing Description ID",
"type": "string",
"format": "iri-reference"
}
},
"forms": [
{
"href": "/things/{id}",
"htv:methodName": "DELETE",
"response": {
"description": "Success response",
"htv:statusCodeValue": 204
},
"additionalResponses": [
{
"description": "TD with the given id not found",
"contentType": "application/problem+json",
"htv:statusCodeValue": 404
}
],
"scopes": "write"
}
]
}
},
"properties": {
"things": {
"@type": "ThingListProperty",
"description": "Collection of Thing Descriptions in the directory",
"uriVariables": {
"id": {
"@type": "ThingID",
"title": "Thing Description ID",
"type": "string",
"format": "iri-reference"
},
"jsonpath": {
"@type": "JSONPathExpression",
"title": "A valid JSONPath expression",
"type": "string"
},
"xpath": {
"@type": "XPathExpression",
"title": "A valid XPath expression",
"type": "string"
},
"query": {
"@type": "SPARQLQuery",
"title": "A valid SPARQL 1.1. query",
"type": "string"
}
},
"forms": [
{
"href": "/things/{id}",
"htv:methodName": "GET",
"response": {
"description": "Success response",
"htv:statusCodeValue": 200,
"contentType": "application/td+json"
},
"additionalResponses": [
{
"description": "TD with the given id not found",
"contentType": "application/problem+json",
"htv:statusCodeValue": 404
}
],
"scopes": "read"
},
{
"href": "/things?jsonpath={jsonpath}",
"htv:methodName": "GET",
"response": {
"description": "Success response",
"contentType": "application/json",
"htv:statusCodeValue": 200
},
"additionalResponses": [
{
"description": "JSONPath expression not provided or contains syntax errors",
"contentType": "application/problem+json",
"htv:statusCodeValue": 400
}
],
"scopes": "search"
},
{
"href": "/things?xpath={xpath}",
"htv:methodName": "GET",
"response": {
"description": "Success response",
"contentType": "application/json",
"htv:statusCodeValue": 200
},
"additionalResponses": [
{
"description": "XPath expression not provided or contains syntax errors",
"contentType": "application/problem+json",
"htv:statusCodeValue": 400
}
],
"scopes": "search"
},
{
"href": "/things?query={query}",
"htv:methodName": "GET",
"response": {
"description": "Success response",
"htv:statusCodeValue": 200
},
"additionalResponses": [
{
"description": "SPARQL query not provided or contains syntax errors",
"contentType": "application/problem+json",
"htv:statusCodeValue": 400
}
],
"scopes": "search"
}
]
},
"sparql": {
"@type": "SPARQLProperty",
"description": "Endpoint for querying the directory with SPARQL",
"forms": [
{
"href": "/sparql",
"htv:methodName": "POST",
"contentType:": "application/x-www-form-urlencoded",
"response": {
"description": "Success response",
"contentType": "application/json",
"htv:statusCodeValue": 200
},
"additionalResponses": [
{
"description": "SPARQL query not provided or contains syntax errors",
"contentType": "application/problem+json",
"htv:statusCodeValue": 400
}
],
"scopes": "search"
},
{
"href": "/sparql",
"htv:methodName": "POST",
"contentType:": "application/sparql-query",
"response": {
"description": "Success response",
"contentType": "application/json",
"htv:statusCodeValue": 200
},
"additionalResponses": [
{
"description": "SPARQL query not provided or contains syntax errors",
"contentType": "application/problem+json",
"htv:statusCodeValue": 400
}
],
"scopes": "search"
}
]
}
},
"events": {
"thingCreated": {
"@type": "ThingCreatedEvent",
"title": "Thing created",
"data": {
"type": "object",
"description": "The schema of created TD event data including the created TD",
"properties": {
"td_id": {
"type": "string",
"format": "iri-reference",
"description": "Identifier of TD in directory"
},
"td": {
"type": "object",
"description": "The created TD in a create event"
}
}
},
"forms": [
{
"op": "subscribeevent",
"href": "/events/thingcreated",
"subprotocol": "sse",
"contentType": "text/event-stream",
"htv:headers": [
{
"description": "ID of the last event for reconnection",
"htv:fieldName": "Last-Event-ID",
"htv:fieldValue": ""
}
],
"scopes": "notifications"
}
]
},
"thingUpdated": {
"@type:": "ThingUpdatedEvent",
"title": "Thing updated",
"data": {
"type": "object",
"description": "The schema of updated TD event data including the TD updates",
"properties": {
"td_id": {
"type": "string",
"format": "iri-reference",
"description": "Identifier of TD in directory"
},
"td_updates": {
"type": "object",
"description": "The partial TD composed of modified TD parts in an update event"
}
}
},
"forms": [
{
"op": "subscribeevent",
"href": "/events/thingupdated",
"subprotocol": "sse",
"contentType": "text/event-stream",
"htv:headers": [
{
"description": "ID of the last event for reconnection",
"htv:fieldName": "Last-Event-ID",
"htv:fieldValue": ""
}
],
"scopes": "notifications"
}
]
},
"thingDeleted": {
"@type": "ThingDeletedEvent",
"title": "Thing deleted",
"data": {
"type": "object",
"description": "The schema of deleted TD event data",
"properties": {
"td_id": {
"type": "string",
"format": "iri-reference",
"description": "Identifier of TD in directory"
}
}
},
"forms": [
{
"op": "subscribeevent",
"href": "/events/thingupdated",
"subprotocol": "sse",
"contentType": "text/event-stream",
"htv:headers": [
{
"description": "ID of the last event for reconnection",
"htv:fieldName": "Last-Event-ID",
"htv:fieldValue": ""
}
],
"scopes": "notifications"
}
]
}
}
} |
I also vote for keeping SPARQL separate and add the following reasons:
Apart from the events, I consider all changes as refactoring because they involve no functional changes to the directory. PRs would be very useful. For events, we can discuss the functional changes in #28 and #42: that is not being able to subscribe to multiple or all events in a single operation. I personally think we should design the API based on requirements (derived from use cases) and not based on what is possible or nicer in a TD. |
I agree with starting from use cases & requirements, but if the W3C is going to provide a normative Thing Description/Thing Model in a specification then it should demonstrate best practices. Combining all events into a single event so that they can all be subscribed to in a single operation seems like a workaround for a missing feature in Thing Description, which suggests there is an additional unfulfilled requirement for that specification. I have filed w3c/wot-thing-description#1082 for that. |
@benfrancis are you able to join the discovery call now? We are going to discuss this in a couple of minutes. |
On my way. |
Notes from the discovery call:
|
Just a comment that wasn't captured in the call today. With the current I think this is a good playground where we can stress the current TD spec and see its strengths and limits. I would introduce what we can in the current discovery spec and continue the discussion of the open questions on the TD spec. I am opening an issue about the problem above. |
For events, I still think But I can live with breaking the event:
into:
The API remains the same and would implicitly allow subscription to multiple:
|
The issue isn't that the event is called "registration", it's that it actually represents three different types of events: created, updated and deleted. Arguably only the first of those is actually a "registration".
Why do you prefer this to:
? (Again, I don't think URIs and URI variables should be fixed in the specification, which would allow either of these examples to be valid.)
|
Please note my example:
From the current spec:
|
I have submitted four pull requests to apply the changes proposed in this issue:
Hopefully this is granular enough to continue this discussion and start to nail down some of the details. If any of these changes are accepted then follow-up PRs will be needed to update the text of the specification to match the machine-readable description of the API in the example Thing Description. Note: Included in these PRs are a collection of semantic annotations which help to identify various interaction affordances, URI variables and data schemas without needing to hard code affordance names, URIs and URI variables in the specification. This is a separate issue being discussed in #144 but the proposed changes don't make as much sense without those annotations. |
Original issue has been dealt with by a set of PRs (@farshidtz to add links afterwards). |
List of merged PRs related to this issue:
|
It seems that the current specification of the TDD Thing Description relies on this @farshidtz's assumption (which was actually taken from the TD spec):
However, the current architecture document gives a less strict definition for Web Things Actions affordances:
Notice that it's using MAY and not MUST. What feels odd in the current TD specification is the fact that the search operations are modeled as properties with
uriVariables
. I wonder if we can evaluate the following refactoring, where they are modeled as actions:In general, it seems that in the current design we are blending design decisions from the REST layer which is just a binding and it could follow a different interaction model than WoT.
As a side note, I still find the usage of URI variables in actions weird as described here.
The text was updated successfully, but these errors were encountered: