Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
229 changes: 206 additions & 23 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@
The generic WoT terminology is defined in [[!wot-architecture11]]: <dfn data-lt="Things">Thing</dfn>, <dfn data-lt="Thing Descriptions">Thing Description</dfn> (in short <dfn>TD</dfn>), <dfn>Partial TD</dfn>, <dfn>Web of Things</dfn> (in short <b><i>WoT</i></b>), <dfn>WoT Interface</dfn>, <dfn>Protocol Bindings</dfn>, <dfn>WoT Runtime</dfn>, <dfn data-lt="consume|consume a TD|consuming a TD">Consuming a Thing Description</dfn>, <dfn>TD Directory</dfn>, <dfn data-lt="Properties">Property</dfn>, <dfn data-lt="Actions">Action</dfn>, <dfn data-lt="Events|WoT-Event">Event</dfn>,
<a data-cite="wot-thing-description11#dataschema">
<dfn>DataSchema</dfn></a>, <a data-cite="wot-thing-description11#form"><dfn data-lt="Forms">Form</dfn></a>,
<a data-cite="wot-thing-description11#securityscheme"><dfn>SecurityScheme</dfn></a>, <a data-cite="wot-thing-description11#nosecurityscheme"><dfn>NoSecurityScheme</dfn></a> etc.
<a data-cite="wot-thing-description11#securityscheme"><dfn>SecurityScheme</dfn></a>, <a data-cite="wot-thing-description11#nosecurityscheme"><dfn>NoSecurityScheme</dfn></a>, <a data-cite="wot-thing-description11#additionalexpectedresponse"><dfn>AdditionalExpectedResponse</dfn></a> etc.
</p>
<p>
<dfn data-plurals="WoT Interactions">WoT Interaction</dfn> is a synonym for <a data-cite="wot-architecture11#dfn-interaction-affordance"><dfn>Interaction Affordance</dfn></a>.
Expand Down Expand Up @@ -1434,15 +1434,95 @@ <h2>The <dfn>ActionInteractionOutput</dfn> interface</h2>
title="Error handling"/>
<figcaption>Error handling in WoT interactions</figcaption>
</figure>
<p class="ednote">
This topic is still being discussed in
<a href="https://github.com/w3c/wot-scripting-api/issues/200">Issue #200</a>.
A standardized error mapping would be needed in order to ensure consistency
in mapping script errors to protocol errors and vice versa. In particular,
when algorithms say "error received from the <a>Protocol Bindings</a>",
that will be factored out as an explicit error mapping algorithm. Currently,
that is encapsulated by implementations.
</p>

<section data-dfn-for="InteractionError">
<h3>The <dfn>InteractionError</dfn> interface</h3>
<p class="note">
Currently, we are looking for wider implementation of the following section.
The algorithm presented here might be subject to changes in the future.
</p>
<p>
Represents an error that occurred during a <a>WoT Interaction</a> with
additional diagnostic information from the <a>Thing</a> in the form of
response data associated with an <a>AdditionalExpectedResponse</a> defined in
the <a>Thing Description</a>.
</p>
<pre class="idl">
[SecureContext, Exposed=(Window,Worker)]
interface InteractionError : Error {
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

WebIDL suggests extending DOMException, I need to update this before merging, since the discussion (Error vs DOMException is still open.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@danielpeintner turns out that if we want to extend DOMException, the "extra data" we carry in the Exception must be serializable. Sadly, InteractionOutput is not serializable as it contains a non-serializable field ( ReadableStream? data). We can:

  • Leave the changes as they are, but we have this inconsistency between the "native" errors and our "custom" error. The inconsistency is that InteractionError does not extend DOMException.
  • We force the thrower of the error to eagerly read the full payload and then throw.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It seems easiest to stick with Error since we are not happy with DOMException anyway.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

It seems we have the same problem with https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error . However, I'm aware that some HTTP clients do not respect the serializable constraint.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Mhh, what are you proposing?

constructor(DOMString message, InteractionOutput data);
readonly attribute InteractionOutput data;
};
</pre>
<p>
The <dfn data-lt="InteractionError.data">data</dfn> attribute represents
the {{InteractionOutput}} object containing the response payload from the
failed <a>WoT Interaction</a>.
</p>
</section>

<section>
<h3>The <dfn>handle interaction error response</dfn> algorithm</h3>
<p>
This algorithm is invoked by any {{ConsumedThing}} method that performs a <a>WoT Interaction</a>.
It processes error responses returned by the <a>Protocol Bindings</a> and determines whether to
throw an {{InteractionError}} or map the response to a {{DOMException}}.
</p>
<p>
To <a>handle interaction error response</a> given |error|, |form:Form| and |response|,
run these steps:
</p>
<ol>
<li>
if |response| is not defined or null, attempt to map |error|
to a suitable {{DOMException}} or, if none, to {{OperationError}}.
Return that error and stop.
</li>
<li>
Let |additionalResponses| be |form|.|additionalResponses|, if it exists.
</li>
<li>
Let |binding| be the binding that was used to make the request which resulted in |response|.
</li>
<li>
If |additionalResponses| is defined, for each |responseEntry:AdditionalExpectedResponse| in
|additionalResponses|:
<ol>
<li>
Let |match| be a boolean expression that checks if |response| matches a |responseEntry| according to |binding|
</li>
<li>
If |responseEntry|.|success| is `false` or not defined and if |match| is `true` for |responseEntry|,
then run these sub-steps:
<ol>
<li>
Let |responseSchema| be |responseEntry|.|schema|, if it exists.
</li>
<li>
Let |errorOutput:InteractionOutput| be the result of running
<a>parse interaction response</a> on |response|, |form|, and
|responseSchema|.
</li>
<li>
Return a newly constructed {{InteractionError}}, using a message
derived from the |binding| or |error| as first argument, and |errorOutput|
as second argument.
</li>
</ol>
</li>
</ol>
</li>
<li>
If no match was found in |additionalResponses| but |binding| indicates
a failure, attempt to map the error
to a suitable {{DOMException}} or other appropriate
error type.
</li>
<li>
Otherwise, return {{OperationError}}.
</li>
</ol>
</section>
</section>

</section> <!-- Handling interaction data -->
Expand Down Expand Up @@ -1635,7 +1715,18 @@ <h3>The <dfn>readProperty()</dfn> method</h3>
using |form| and the optional URI templates given in |options|.|uriVariables|.
</li>
<li>
If the request fails, [=reject=] |promise| with the error received from the <a>Protocol Bindings</a> and stop.
If the request fails with error |receivedError| and optionally |failedResponse|,
run the followingsub-steps:
<ol>
<li>
let |error| be the result of running
<a>handle interaction error response</a> given the |receivedError|
|form| and |failedResponse|.
</li>
<li>
[=Reject=] |promise| with |error| and stop.
</li>
</ol>
</li>
<li>
Let |response| be the response received to the request.
Expand Down Expand Up @@ -1678,11 +1769,26 @@ <h3>The <dfn>readMultipleProperties()</dfn> method</h3>
<li>
Let |result:object| be an object and for each string |name:string| in |propertyNames| add a property with key |name| and the value `null`.
</li>
<li>
If this cannot be done with a single request with the <a>Protocol Bindings</a>, [=reject=] |promise| with a
{{NotSupportedError}} and stop.
</li>
Comment thread
relu91 marked this conversation as resolved.
<li>
Make a request to the underlying platform (via the <a>Protocol Bindings</a>) to retrieve the <a>Property</a> values given by |propertyNames| with |form| and optional URI templates given in |options|' |uriVariables|.
</li>
<li>
If this cannot be done with a single request with the <a>Protocol Bindings</a>, [=reject=] |promise| with a {{NotSupportedError}} and stop.
If the request fails with error |receivedError| and optionally |failedResponse|,
run the following sub-steps:
<ol>
<li>
let |error| be the result of running
<a>handle interaction error response</a> given the |receivedError|
|form| and |failedResponse|.
</li>
<li>
[=Reject=] |promise| with |error| and stop.
</li>
</ol>
</li>
<li>
Process the response and for each |key| in |result|, run the following
Expand Down Expand Up @@ -1750,7 +1856,18 @@ <h3>The <dfn>readAllProperties()</dfn> method</h3>
If this cannot be done with a single request with the <a>Protocol Bindings</a> of the <a>Thing</a>, then [=reject=] |promise| with a {{NotSupportedError}} and stop.
</li>
<li>
If the request fails, [=reject=] |promise| with the error received from the <a>Protocol Bindings</a> and stop.
If the request fails with error |receivedError| and optionally |failedResponse|,
run the following sub-steps:
<ol>
<li>
let |error| be the result of running
<a>handle interaction error response</a> given the |receivedError|
|form| and |failedResponse|.
</li>
<li>
[=Reject=] |promise| with |error| and stop.
</li>
</ol>
</li>
<li>
Process the reply and let |result:object| be an object with the keys and values obtained in the reply.
Expand Down Expand Up @@ -1820,7 +1937,18 @@ <h3>The <dfn>writeProperty()</dfn> method</h3>
|options|' |uriVariables|.
</li>
<li>
If the request fails, [=reject=] |promise| with the error received from the <a>Protocol Bindings</a> and stop.
If the request fails with error |receivedError| and optionally |failedResponse|,
run the following sub-steps:
<ol>
<li>
let |error| be the result of running
<a>handle interaction error response</a> given the |receivedError|
|form| and |failedResponse|.
</li>
<li>
[=Reject=] |promise| with |error| and stop.
</li>
</ol>
</li>
<li>
Otherwise [=resolve=] |promise|.
Expand Down Expand Up @@ -1904,8 +2032,18 @@ <h3>The <dfn>writeMultipleProperties()</dfn> method</h3>
with a {{NotSupportedError}} and stop.
</li>
<li>
If the request fails, return the error received from the
<a>Protocol Bindings</a> and stop.
If the request fails with error |receivedError| and optionally |failedResponse|,
run the following sub-steps:
<ol>
<li>
let |error| be the result of running
<a>handle interaction error response</a> given the |receivedError|
|form| and |failedResponse|.
</li>
<li>
[=Reject=] |promise| with |error| and stop.
</li>
</ol>
</li>
<li>
Otherwise [=resolve=] |promise|.
Expand Down Expand Up @@ -1993,8 +2131,18 @@ <h3>The <dfn>observeProperty()</dfn> method</h3>
optional URI templates given in |options|' |uriVariables|.
</li>
<li>
If the request fails, [=reject=] |promise| with the error received from
the <a>Protocol Bindings</a> and stop.
If the request fails with error |receivedError| and optionally |failedResponse|,
run the following sub-steps:
<ol>
<li>
let |error| be the result of running
<a>handle interaction error response</a> given the |receivedError|
|form| and |failedResponse|.
</li>
<li>
[=Reject=] |promise| with |error| and stop.
</li>
</ol>
</li>
<li>
[=map/Set=] |thing|.{{ConsumedThing/[[activeObservations]]}}[|propertyName] to |subscription| and [=resolve=] |promise|.
Expand Down Expand Up @@ -2083,7 +2231,18 @@ <h3>The <dfn>invokeAction()</dfn> method</h3>
Make a request to the underlying platform (via the <a>Protocol Bindings</a>) to invoke the <a>Action</a> identified by |actionName| given |args| and |options|.|uriVariables|.
</li>
<li>
If the request fails locally or returns an error over the network, [=reject=] |promise| with the error received from the <a>Protocol Bindings</a> and stop.
If the request fails with error |receivedError| and optionally |failedResponse|,
run the following sub-steps:
<ol>
<li>
let |error| be the result of running
<a>handle interaction error response</a> given the |receivedError|
|form| and |failedResponse|.
</li>
<li>
[=Reject=] |promise| with |error| and stop.
</li>
</ol>
</li>
<li>
Let |value| be the reply returned in the reply.
Expand Down Expand Up @@ -2172,8 +2331,18 @@ <h3>The <dfn>subscribeEvent()</dfn> method</h3>
and optional subscription data given in |options|.|data|.
</li>
<li>
If the request fails, [=reject=] |promise| with the error received from
the <a>Protocol Bindings</a> and stop.
If the request fails with error |receivedError| and optionally |failedResponse|,
run the following sub-steps:
<ol>
<li>
let |error| be the result of running
<a>handle interaction error response</a> given the |receivedError|
{{Subscription/[[form]]}} and |failedResponse|.
</li>
<li>
[=Reject=] |promise| with |error| and stop.
</li>
</ol>
</li>
<li>
[=map/Set=] |eventName| to |thing|.{{ConsumedThing/[[activeSubscriptions]]}}[|eventName|] to |subscription|.
Expand Down Expand Up @@ -2389,8 +2558,22 @@ <h4>The <dfn>stop()</dfn> method</h4>
unsubscribe data given in |options|.|data|.
</li>
<li>
If the request fails, [=reject=] |promise| with the error received from
the <a>Protocol Bindings</a> and stop.
If the request fails with error |receivedError| and optionally |failedResponse|,
run the following sub-steps:
<ol>
<li>
let |error| be the result of running
<a>handle interaction error response</a> given the |receivedError|
|unsubscribeForm| and |failedResponse|.
</li>
<li>
[=Reject=] |promise| with |error| and stop.
</li>
<li>
If the underlying platform receives further notifications for this
subscription, implementations SHOULD silently suppress them.
</li>
</ol>
Comment thread
danielpeintner marked this conversation as resolved.
</li>
<li>
Otherwise:
Expand Down