In the context of the Web of Things (WoT), a Binding Template is a blueprint that gives guidance on how to implement a specific IoT protocol, data format or IoT platform. The Core Binding Templates specification explains the overall mechanism and requirements for any binding to follow. This document gives implementation guidelines regarding the Constrained Application Protocol (CoAP), which is a specialized web transfer protocol for use with constrained nodes and constrained (e.g., low-power, lossy) networks.

More specifically, this document defines a set of vocabulary terms that can be used inside a Thing Description document, and associated rules which allow to describe WoT operations using CoAP over the network. Additionally, relevant examples are provided to showcase different vocabulary terms and the associated behavior.

This document is a work in progress

Introduction

The Constrained Application Protocol (CoAP) [[RFC7252]] is a specialized web transfer protocol for use with constrained nodes and constrained (e.g., low-power, lossy) networks. The nodes often have 8-bit microcontrollers with small amounts of ROM and RAM, while constrained networks such as IPv6 over Low-Power Wireless Personal Area Networks (6LoWPANs) often have high packet error rates and a typical throughput of 10s of kbit/s. The protocol is designed for machine-to-machine (M2M) applications such as smart energy and building automation.

This document describes how to present devices that use CoAP in a Thing Description. In particular, the document explains how to create valid Forms for the different operations that CoAP can perform.

Forms of a Thing Description instance with CoAP Binding complies with this specification if it follows the normative statements in and .

A JSON Schema [[?JSON-SCHEMA]] to validate Thing Description instances containing CoAP Binding is provided in the GitHub repository.

Protocol Overview

The interaction model of CoAP [[RFC7252]] is similar to the client/server model of HTTP [[RFC7230]]: A CoAP client sends requests to a CoAP server and receives responses. Requests indicate the action to be performed (e.g., GET, POST, PUT, DELETE) by means of a CoAP method code. Responses carry a CoAP status code that indicates success or failure. Requests and response may carry a representation in a CoAP content format (i.e., content type with optional content coding).

The parameters and metadata of requests and responses are carried in CoAP options. CoAP defines a set of common options (e.g., URI path and query components, Accept and Content-Format) and allows new options to be defined. Options are generally set when using certain CoAP features, such as the Observe option being set when Observing Resources in CoAP [[RFC7641]].

The following sections provide an overview of the CoAP features defined at the time of writing and give examples of a how these can be used in a [[[WOT-THING-DESCRIPTION]]]. The vocabulary terms used in these examples are defined in section [[[#vocabulary]]].

Requests/Responses

Things accessible via CoAP provide interaction affordances that direct Consumers to send CoAP requests to a CoAP endpoint. The Thing processes these requests and sends appropriate CoAP responses.

The target resource is specified in the Thing Description by the href member of a form, using one of the CoAP URI schemes (see section [[[#url]]]). The request method (e.g., "GET", "PUT", "POST", or "DELETE") is specified using the cov:method member of a form.

{
    "@context": "https://www.w3.org/2022/wot/td/v1.1",
    ...
    "properties": {
        "status": {
            "type": "string",
            "readOnly": true,
            "forms": [{
                "cov:method": "GET",
                "href": "coap://[2001:DB8::1]/status",
                "contentType": "text/plain;charset=utf-8",
                "op": ["readproperty"]
            }]
        }
    }
}

The cov:method member may be omitted if the request method is the default for the operation (see section [[[#default-mappings]]]).

{
    "@context": "https://www.w3.org/2022/wot/td/v1.1",
    ...
    "properties": {
        "status": {
            "type": "string",
            "readOnly": true,
            "forms": [{
                "href": "coap://[2001:DB8::1]/status",
                "contentType": "text/plain;charset=utf-8"
            }]
        }
    }
}

The contentType and contentCoding members of a form specify the CoAP content format of the request and/or response. In CoAP, combinations of content type and content coding are encoded using standardized values listed in the IANA CoAP Content-Formats registry. Therefore, not every combination of content type and content coding can be used with CoAP. Furthermore, even parameters are included in the mapping: in [[[#example-request-defaults]]], the content type text/plain;charset=utf-8 would be mapped to Content-Format ID 0. Omitting the charset parameter, for instance, would break a literal mapping from content type to Content-Format in this case.

Section [[[#content-negotiation]]] introduces the additional vocabulary terms cov:contentFormat and cov:accept to deal with ambiguities of content types and content codings in the context of CoAP, and to give Consumers guidance for the content negotiation process.

Content Negotiation

Content negotiation in CoAP is used to negotiate the representation of CoAP resources that may have different representations available.

Content negotiation is accomplished through the use of CoAP Accept and Content-Format options. The CoAP Accept option is used by clients to request a particular content format, while the Content-Format option is used by clients and servers to indicate the content format of the representation in requests and responses, respectively.

Mapping the string-based contentType and contentCoding fields to a numeric Content-Format can be difficult for a Consumer for a number of reasons: First, a Consumer needs to be aware of all potential mappings between the string-based and the numerical representations. Furthermore, since there is no well-defined algorithm for converting a combination of contentType and contentCoding to a CoAP Content-Format, the process might be prone to error.

Therefore, this document introduces the vocabulary term cov:contentFormat for providing a hint to simplify the conversion for a Consumer. It can be used in all Thing Description classes that contain the contentType and contentCoding fields. If the field cov:contentFormat is present, it must match the string representation expressed by contentType and contentCoding. Corresponding with the default contentType value application/json, Consumers are supposed to assume a Content-Format value 50 if cov:contentFormat and application/json is not present.

Forms may contain a cov:accept field to explicitly require a Consumer to provide an Accept option. If a cov:accept member is present in a Form, then the Consumer must use the contained value in an Accept option when requesting the described resource.

In the case of the following example, a Consumer trying to invoke the start Action would include a Content-Format option with value 50 (application/json) and an Accept option with value 60 (application/cbor) in its request when choosing the first Form provided. Since both forms have the same href, use of Accept option allows the Consumer to choose the correct form.

                {
                    "@context": "https://www.w3.org/2022/wot/td/v1.1",
                    ...
                    "actions": {
                        "start": {
                            "input": { "type": "integer" },
                            "output": { "type": "string" },
                            "forms": [
                                {
                                    "href": "coap://[2001:DB8::1]/start",
                                    "cov:accept": 60,
                                    "response": {
                                        "contentType": "application/cbor",
                                        "cov:contentFormat": 60
                                    }
                                },
                                {
                                    "href": "coap://[2001:DB8::1]/start",
                                    "contentType": "application/cbor",
                                    "cov:contentFormat": 60,
                                    "cov:accept": 50,
                                    "response": {
                                        "contentType": "application/json",
                                        "cov:contentFormat": 50
                                    }
                                }
                            ]
                        }
                    }
                }
                

Caching

CoAP features two mechanisms to make efficient use of network resources and minimize the number of required transmissions. First, a CoAP client may store responses to requests in order to satisfy future requests without sending a new request. A stored response may be used if it is still valid, i.e., if the response's Max-Age value has not been exceeded. Second, a CoAP client may validate a stored response by sending a new request with the ETag from the stored response. This allows the server to quickly respond with a 2.03 (Valid) response if the stored response is still valid.

Consumers are generally expected to make use of both mechanisms to minimize the number of required CoAP transmissions.

Polling Resources

A CoAP client may need a current representation of a resource over a period of time. In this case, the client may poll the CoAP server periodically for new content, taking advantage of caching to keep traffic to a minimum.

It is important to note that a response's Max-Age is independent of how often a client polls. For example, if a response contains the current position of an aircraft, after less than a second it can no longer be assumed that the aircraft is still in the same position. This means the server would set Max-Age to 0 in the response, indicating the response cannot be reused for a future request.

If a client polls too frequently, a server may send a 4.29 (Too Many Requests) response [[RFC8516]]. This error response is cacheable, with the Max-Age indicating after which time the client is allowed to try again.

In a form, the cov:minPollingInterval member can be used to provide a hint of what minimum polling interval the server is willing to accept. (This doesn't mean that the client won't get a 4.29 response if it complies; just that the client will most likely get a 4.29 response if it doesn't.)

{
    "@context": "https://www.w3.org/2022/wot/td/v1.1",
    ...
    "properties": {
        "status": {
            "type": "string",
            "readOnly": true,
            "forms": [{
                "href": "coap://[2001:DB8::1]/status",
                "contentType": "text/plain;charset=utf-8",
                "cov:minPollingInterval": 60
            }]
        }
    }
}
        

Observing Resources

As a significant improvement over polling, CoAP provides a mechanism for clients to "observe" resources [[RFC7641]], i.e., to request notifications from the server whenever the resource changes. This is especially useful in the Web of Things where many Things are expected to have resources that change over time, such as sensor readings.

A resource can be observed by sending a `GET` or `FETCH` [[RFC8132]] request with the `Observe` option set. The server will respond with the current representation of the resource, and will send notifications of future changes to the client. A server is not required to support the `Observe` option for all resources; a resource without `Observe` support can still be manually observed by polling it at regular intervals.

{
    "@context": "https://www.w3.org/2022/wot/td/v1.1",
    ...
    "properties": {
        "status": {
            "type": "string",
            "readOnly": true,
            "forms": [{
                "cov:method": "GET",
                "href": "coap://[2001:DB8::1]/status",
                "contentType": "text/plain;charset=utf-8",
                "op": ["observeproperty", "unobserveproperty"]
            }]
        }
    }
}

Block-wise Transfers

CoAP supports block-wise transfers to allow large resource representations to be transferred between clients and servers. This feature enables clients and servers to request or provide resource representations in smaller blocks, which can be useful when constrained network conditions make it undesirable to transfer large amounts of data at once.

At the time of writing, CoAP supports two mechanisms for block-wise transfers: Block-Wise Transfers [[RFC7959]] and Block-Wise Transfer Options Supporting Robust Transmission [[RFC9177]]. In a form, support for these can be indicated by a cov:blockwise or cov:quickblockwise member, respectively.

{
    "@context": "https://www.w3.org/2022/wot/td/v1.1",
    ...
    "properties": {
        "status": {
            "type": "string",
            "readOnly": true,
            "forms": [{
                "href": "coap://[2001:DB8::1]/status",
                "contentType": "text/plain;charset=utf-8",
                "cov:blockwise": { }
            }]
        }
    }
}

Additionally, a cov:blockwise or cov:quickblockwise member may indicate relevant parameters, such as the largest block size that may be used in a Block2 Option.

{
    "@context": "https://www.w3.org/2022/wot/td/v1.1",
    ...
    "properties": {
        "status": {
            "type": "string",
            "readOnly": true,
            "forms": [{
                "href": "coap://[2001:DB8::1]/status",
                "contentType": "text/plain;charset=utf-8",
                "cov:blockwise": {
                    "cov:block2Size": 64
                }
            }]
        }
    }
}

Conditional Requests

With conditional requests, a CoAP client can include conditions in a request that specify how the server should process the request. If the server cannot satisfy the conditions, it returns a 4.12 (Precondition Failed) response.

At the time of writing, CoAP supports three types of conditional requests:

Conditional requests are typically used in the context of larger, multi-step workflows. For example, a CoAP client might want to make sure that a resource has not been modified before it performs some action on it. Therefore, no vocabulary is provided for driving conditional requests from the Thing Description. Instead, consumers are expected to be familiar with the specifics of the workflows in which they are participating and to use conditional requests accordingly.

Hop Limit

The CoAP Hop-Limit option [[RFC8768]] limits the number of hops a CoAP message can take before it is considered undeliverable. This prevents infinite message loops in CoAP networks.

In a form, the cov:hopLimit member can be used to set the desired hop limit for a particular CoAP request.

{
    "@context": "https://www.w3.org/2022/wot/td/v1.1",
    ...
    "properties": {
        "status": {
            "type": "string",
            "readOnly": true,
            "forms": [{
                "href": "coap://[2001:DB8::1]/status",
                "contentType": "text/plain;charset=utf-8",
                "cov:hopLimit": 5
            }]
        }
    }
}

URI Schemes

CoAP uses the following Uniform Resource Identifier (URI) schemes for identifying CoAP resources and providing a means of locating the resource:

URI Scheme Reference
coap [[RFC7252]]
coap+tcp [[RFC8323]]
coap+ws [[RFC8323]]
coaps [[RFC7252]]
coaps+tcp [[RFC8323]]
coaps+ws [[RFC8323]]

See the Uniform Resource Identifier (URI) Schemes registry for the complete list of CoAP URI schemes.

CoAP Vocabulary

This section describes the vocabulary used in CoAP. A protocol binding implementation should use the vocabulary defined in this section to describe the different configuration that can be used to exchanged data between Web of Things.

Form terms

Vocabulary term Description Assignment Type
cov:method Indicates the CoAP method to be used in the request. optional string (e.g., GET, PUT, POST, DELETE, FETCH, iPATCH, or PATCH)

(See the CoAP Method Codes registry for the set of possible values.)

cov:minPollingInterval Provides a hint of what minimum polling interval (in seconds) the server is willing to accept before rejecting the client with a 4.29 (Too Many Requests) response [[RFC8516]]. optional unsignedInt
cov:blockwise Indicates that block-wise transfer [[RFC7959]] is supported. optional BlockWiseTransferParameters
cov:qblockwise Indicates that quick block-wise transfer [[RFC9177]] is supported. optional BlockWiseTransferParameters
cov:hopLimit Indicates that a CoAP Hop-Limit option [[RFC8768]] should be included in the request. optional unsignedByte
cov:contentFormat Specifies the Content-Format to be used by a client for input data and the Content-Format to be used by a server for output data (where applicable). The value must be the numeric Content-Format ID registered with IANA for the combination of the contentType and contentCoding specified in the same form. optional unsignedShort
cov:accept Indicates that a Consumer must include an Accept option [[RFC7252]] with the given value when requesting the resource associated with this Form. optional unsignedShort

Response terms

The following vocabulary terms are usable in the ExpectedResponse and AdditionalExpectedResponse classes.

Vocabulary term Description Assignment Type
cov:contentFormat Specifies the Content-Format to be used by a client for input data and the Content-Format to be used by a server for output data (where applicable). The value must be the numeric Content-Format ID registered with IANA for the combination of the contentType and contentCoding specified in the same form. optional unsignedShort

BlockWiseTransferParameters

Vocabulary term Description Assignment Type
cov:block2Size Indicates the largest block size that may be used in a Block2 or Q-Block2 Option optional unsignedShort (one of 16, 32, 64, 128, 256, 512, or 1024)
cov:block1Size Indicates the largest block size that may be used in a Block1 or Q-Block1 Option optional unsignedShort (one of 16, 32, 64, 128, 256, 512, or 1024)

Mappings

This section describes the strategies and default values to use protocol specific concepts within the WoT Interaction model.

Default mappings

Operation Default Binding
readproperty "cov:method": "GET"
writeproperty "cov:method": "PUT"
observeproperty "cov:method": "GET"
unobserveproperty "cov:method": "GET"
readmultipleproperties "cov:method": "GET"
writemultipleproperties "cov:method": "PUT"
readallproperties "cov:method": "GET"
writeallproperties "cov:method": "PUT"
observeallproperties "cov:method": "GET"
unobserveallproperties "cov:method": "GET"
invokeaction "cov:method": "POST"
queryaction "cov:method": "GET"
cancelaction "cov:method": "POST"
queryallactions "cov:method": "GET"
subscribeevent "cov:method": "GET"
unsubscribeevent "cov:method": "GET"
subscribeallevents "cov:method": "GET"
unsubscribeallevents "cov:method": "GET"

For the `observeproperty` and `subscribeevent` operations, a consumer SHOULD add an `Observe` option to `GET` or `FETCH` requests. Note, however, that using `FETCH` for the `observeproperty` operation is NOT RECOMMENDED, as `FETCH` requests must contain a `Content-Format` option which can imply that the request payload must not be empty. For the `subscribeevent` operation, on the other hand, using `FETCH` is RECOMMENDED if the Event Affordance expects the consumer to provide data described by the `subscription` field.

If the server's response does not contain an `Observe` option, this indicates that the requested server does not support observe, and that the consumer SHOULD fall back to polling instead (see section [[[#polling-resources]]]). Consequently, a consumer can always fall back to polling a resource if observing that resource is permanently or temporarily not possible. In fact, a typical CoAP client implementation is to poll for as long as the client is interested in having a current representation, setting the `Observe` option each time. As long as the client is receiving notifications, it doesn't need to poll; as soon as the notifications are missing, the client polls again with the `Observe` option set.

The `unobserveproperty` and `unsubscribeevent` operations with CoAP observe MUST be performed as specified in section 3.6 of [[RFC7641]]. Note that this operation can be performed either actively (i.e., by sending an explicit deregistration request) or passively (by "forgetting" the observe relation and sending a reset message after receiving the next notification response from the server). For the `unobserveproperty` and `unsubscribeevent` operations to work, they MUST refer to the same resource as the matching `observeproperty` and `subscribeevent` operations. It is therefore RECOMMENDED to always include these operations in the same form as their counterparts when defining them for an affordance. If no `unobserveproperty` or `unsubscribeevent` operation is defined for an observable property or an event, it SHOULD be assumed that the "passive" deregistration variant is meant to be used with the respective affordance.

The same considerations apply to the operations `observemultipleproperties`, `observeallproperties`, `subscribemultipleevents`, `subscribeallevents`, and their respective `unobserve-` and `unsubscribe-` counterparts. Note, however, that it is NOT RECOMMENDED to use the `observeallproperties` and `subscribeallevents` operations with constrained devices that provide many properties and/or events, as the observe notifications may become too large for constrained devices or their surrounding environments to handle.

In the case of Event Affordances, CoAP Observe only supports a simply event notification mechanism that corresponds with the `data` field of the `EventAffordance` class within a Thing Description. More complex event mechanisms may be supported via the procedures defined in specifications such as [[?I.D.-coap-pubsub]] or [[?I.D.-stp]] in the future.

Possible mappings

TODO: This section should describe other mappings that can be used by TD designers. It is meant to be informative but it provides guidelines for implementers.