-
Notifications
You must be signed in to change notification settings - Fork 63
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
Actions with cancel and query operations, the meaning of input and output, dynamic href #1408
Comments
Call of 02.03:
|
@egekorkan Thanks for this detailed analysis. I think most of these issues were already discussed in #302, where I highlighted the problem that it's really not clear how to use these operations without requiring additional out-of-band information like we have in the Core Profile. As you have identified, the most fundamental constraint is the lack of a way to clearly describe dynamic resources in a Thing Description. With out-of-band information provided in a profile this is fine. For example, below are the action sections of the example Thing Description I've proposed for the Core Profile in w3c/wot-profile#91: "actions": {
"fade": {
"title": "Fade",
"description": "Fade the lamp to a given level",
"input": {
"type": "object",
"properties": {
"level": {
"type": "integer",
"minimum": 0,
"maximum": 100,
"unit": "percent"
},
"duration": {
"type": "integer",
"minimum": 0,
"unit": "milliseconds"
}
}
},
"forms": [{"href": "./actions/fade"}]
}
},
...
"forms": [
{
"op": "queryallactions",
"href": "./actions"
},
] All that's needed is to define a top level endpoints for actions and the protocol binding section of the profile defines the rest. Trying to express the Core Profile's full protocol binding for (Note that the intention of this example is not that a Thing would ever expose a Thing Description like this, it's more to illustrate to what extent implementing the Core Profile can simplify the implementation of complex interactions for conformant Producers and Consumers and to illustrate the Core Profile's protocol binding in the form of an informative Thing Description). "actions": {
"fade": {
"title": "Fade",
"description": "Fade the lamp to a given level",
"input": {
"type": "object",
"properties": {
"level": {
"type": "integer",
"minimum": 0,
"maximum": 100,
"unit": "percent"
},
"duration": {
"type": "integer",
"minimum": 0,
"unit": "milliseconds"
}
}
},
"forms": [
{
"op": "invokeaction",
"href": "./actions/fade",
"htv:methodName": "POST",
"contentType": "application/json",
"htv:headers": [{
"htv:fieldName": "Accept",
"htv:fieldValue": "application/json"
}],
"response": {
"htv:statusCodeNumber": 201,
"htv:headers": [
{
"htv:fieldName": "Location",
"htv:fieldValue": "/fade/{id}"
}
],
"contentType": "application/json",
"schema": "actionStatus"
},
"additionalResponses": [
{
"htv:statusCodeNumber": 200,
"htv:headers": [
{
"htv:fieldName": "Location",
"htv:fieldValue": "/fade/{id}"
}
],
"contentType": "application/json",
"schema": "actionStatus"
}
]
},
{
"op": "queryaction",
"href": "./actions/fade/{id}",
"htv:methodName": "GET",
"htv:headers": [{
"htv:fieldName": "Accept",
"htv:fieldValue": "application/json"
}],
"response": {
"contentType": "application/json",
"schema": "actionStatus"
}
},
{
"op": "cancelaction",
"href": "./actions/fade/{id}",
"htv:methodName": "DELETE",
"contentType": "application/json"
}
],
"uriVariables": {
"id": {
"type": "string",
"description": "identifier of action request"
}
}
}
}
...
"forms" [
{
"op": "queryallactions",
"href": "./actions",
"htv:methodName": "GET",
"htv:headers": [{
"htv:fieldName": "Accept",
"htv:fieldValue": "application/json"
}],
"response": {
"contentType": "application/json",
"schema": "actionStatusList"
}
}
]
...
"schemaDefinitions": {
"actionStatus": {
"type": "object",
"properties": {
"status": {
"type": "string",
"enum": [
"pending",
"running",
"completed",
"failed"
]
},
"error": {
"type": "object"
},
"href": {
"type": "string",
"format": "uri",
"const": "./actions/fade/{id}"
}
},
"required": [
"status"
]
},
"actionStatusList": {
"type": "object",
"additionalProperties": {
"type": "array",
"items": {
"type": "object",
"properties": {
"status": {
"type": "string",
"enum": [
"pending",
"running",
"completed",
"failed"
]
},
"error": {
"type": "object"
},
"href": {
"type": "string",
"format": "uri",
"const": "./actions/fade/{id}"
}
},
"required": [
"status"
]
}
}
}
} You can see how complicated this gets, and there are still some open issues I haven't been able to resolve due to limitations of the Thing Description specification. As we discussed in #302 it's also still not clear how a Consumer (without the out-of-band information in the profile) would automatically be able to understand how the value of the In #302 (comment) I suggested two potential paths forward for dealing with these more complex use cases:
What we did in the end was to define the HTTP API for action queues in the Core Profile, and add the basic Basically the conclusion in the Profile task force was that it's fine for a profile to provide out-of-band information which goes beyond what can be described declaratively in a Thing Description, and that the Thing Description specification should eventually try to catch up. To address your proposals for normative changes... @egekorkan wrote:
This isn't always the case in the Core Profile protocol binding. The In other words, the output data schema always describes the output of the physical action, which is not necessarily the response to the Edit: Also, what would this mean in a protocol where there is no response to an invokeaction request, e.g. a WebSocket protocol?
I'm not opposed to this, but does this keyword really make any sense beyond HTTP? Also note that in my example above the action can be used both synchronously and asynchronously! What value would you use then?
I definitely don't think actions should be asynchronous by default. Because a) This is the more complex case and b) the distinction doesn't even make sense in some protocols.
As mentioned above, this conflicts with the current specification of the Core Profile where it is always the result of the physical action.
I do this the other way around in the examples above. In the asynchronous case, the
That's OK with me. Note that in the examples above the "input" to
I agree they are open to interpretation, as is illustrated by the differences in the approaches you and I took described above. However, I think this applies to lots of other existing operations too. Explanatory text would be welcome, but can only go so far.
I hope to have an implementation of the Core Profile in WebThings Gateway to test (properties and events are already implemented, actions still need some work). However, my intention is to use the simplified Thing Description style show in my first example and rely on the Core Profile protocol binding to describe the rest. That would mean that only Consumers which implement the Core Profile would be able to use the |
@egekorkan wrote:
I agree that some of these features (e.g. an asynchronous action queue) are very difficult to describe without out-of-band information (e.g. in a profile), and that ideally it would be possible to describe all possible interactions in a Thing Description. However, as we've known for a long time there are already many existing IoT APIs (e.g. the Web Thing API) which can't be completely described by a WoT Thing Description because a Thing Description is still not (and in my opinion can never be) expressive enough to cover all possible use cases. The fact that a profile is able to provide a concrete protocol binding which goes beyond what is possible to describe declaratively in a Thing Description alone is what has made it possible for the WebThings platform to move towards W3C compliance. If the action queue part of the protocol binding has to be removed from the Core Profile because it can't also be described declaratively in a Thing Description, then there is no way for the the WebThings platform to be made W3C compliant without also removing features (i.e. action queues) from the platform. That doesn't seem acceptable to me. In conclusion:
|
from today's TD call:
|
Oh, sorry, this issue needs to be reopened, I linked the wrong issue in #1447 |
I could not really separate this into multiple issues. There are also multiple issues and PRs on this that I summarize below:
After #1208 is merged, we have
cancelaction
andqueryaction
operations. First of all, we need example TDs that have these operations. For the sake of this issue, they can look like the following (taken from https://github.com/w3c/wot-thing-description/tree/main/proposals/hypermedia-control-2):Given that we cannot put dynamic/templating based URLs (i.e.
"href": "/fade/{myActionID}",
) without a way to understand how to provide the value ofmyActionID
we have to have static href. Let's assume this is indeed the case until the Dynamic href chapter below.There are still the following issues:
invokeaction
is responded with a payload, this payload corresponds to the schema defined byoutput
. Given that the action can be synchronous and still providequeryaction
andcancelaction
, it means that the Consumer can query it while waiting for the response. If it is asynchronous, the Consumer will receive immediately a response (or no response at all) and will query the action later. This means that we have to add/change the following normative text:async
keyword in the same level asidempotent
like I have illustrated (pun intended) in Issue [vocabulary] Consider adding keyword to describe synchronous actions #890 . The default value can betrue
. This allows the Consumer to decide when to doqueryaction
. If the action does not havecancelaction
orqueryaction
, this information can be still useful since a property can give information on the action state as well, like a robot arm's position property when a movement-related action is invoked.output
is "related" withinvokeaction
and not with the other operations. The current text saysUsed to define the output data schema of the Action.
Doing this change means that the response ofqueryaction
can be different thaninvokeaction
. We can say that it is the same and that a different output should be described byexpectedResponse
in some way.input
is "related" toinvokeaction
and not with the other operations. This means that it is not possible to describe that one needs to provide input tocancelaction
orqueryaction
.Dynamic href
We can allow dynamic
href
s, they are actually already allowed via the use ofuriVariables
. Meaning that the following action is valid:Of course, the
myActionID
uri variable contains out-of-band information since it can be in the body of the response of theinvokeaction
(where it would be in theoutput
) or in the header, like it is done in the "core" profile https://w3c.github.io/wot-profile/#async-action-response . Maybe that is fine?Notes
Sorry for noticing these implications this late. I did not see or forgot that we have
cancelaction
andqueryaction
now. My proposals are normative changes but it is technically still possible to have them after the WD. These will not have a big effect on testing since I have been providing TDs with thesynchronous
keyword for a couple of plugfests. See https://github.com/w3c/wot-testing/blob/main/events/2021.09.Online/TD/TDs/TUM/flask-based/DobotMagician.td.jsonld . The other changes do not introduce new keywords but change the current assertion text.The text was updated successfully, but these errors were encountered: