API Reference



1. Introduction

The IoT RESTful API defines a RESTful web service interface, in which users can perform CREATE, READ, UPDATE, and DELETE (CRUD) actions to any uniquely-identifiable resources in the service.

The OGC IoT RESTful service interface is different from the other OGC web services, in that it is based on RESTful web service style and JSON encoding. The OGC IoT RESTful API is inspired by the OASIS Open Data Protocol (OData), which defines a general-purpose RESTful service interface. The IoT RESTful service interface is very similar to the OData but specifically designed for the IoT.

Besides the OData, the IoT RESTful service interface also leverages the existing and widely implemented OGC standards. For example, the capabilities part of the OGC IoT RESTful service interface adapts some elements from the GetCapabilities response defined in the OWS Common by converting the XML encoding into the JSON encoding.

The OGC IoT RESTful API consists of two major profiles: the Sensing Profile and the Tasking Profile. The Sensing Profile is designed based on the OGC Sensor Observation Service (SOS) specification in which defines an interoperable framework to manage and access sensors and observations. The Tasking Profile is based on the OGC Sensor Planning Service (SPS) specification, in which defines an interoperable way to submit tasks to control sensors and actuators.

In the following subsections, we first describe the URI Components for addressing resources and possible query options. Then we define the protocol of retrieving the capabilities document. Finally, we explain the CRUD requests and responses in the Sensing Profile and Tasking Profile.

In this API reference page, we mainly focus on describing the behaviour of the OGC IoT RESTful API without presenting detailed examples. Instead, the complete data model and JSON examples of resources can be found in the Data Model page.

2. URI Components

Similar to the OASIS OData, the OGC IoT RESTful API groups the same types of entities into collections. Each entity has a unique identifier and one to many properties. Also, in the case of an entity holding a relationship with entities in another collection, this entity has a navigation property (i.e., a link) linking to other entities. The complete data model and JSON examples of resources can be found in the Data Model page.

Therefore, in order to perform CRUD actions on the resources, the first step is to address to the target resource(s) through URI. There are three major URI components used in this API: the service root URI, the Resource Path, and the Query Options. The service root URI is the location of the IoT RESTful service. By attaching the resource path after the service root URI, users can address to different kinds of resources such as a collection, an entity, a property, or a navigation property. Finally, when users perform the READ (i.e., HTTP GET) action on resource(s), users can apply query options to further process the addressed resources, such as sorting by properties and filtering with criteria.

2.1 Resource Path

The resource path comes right after the service root URI and can be used to address to different resources. The following lists the general usages of the resource path.

Usage 1: No resource path

If a user request does not include any resource path, the IoT RESTful service returns a list of collection names as the service document.

URI Pattern: SERVICE_ROOT_URI

Response: A list of collection names.

Example: http://demo.student.geocens.ca:8080/SWIOT_V0.9/

Usage 2: Address to an entity collection

To address to an entity collection, users can simply put the collection name after the service root URI. The service returns a list of all the entities in the specified collection.

URI Pattern: SERVICE_ROOT_URI/COLLECTION_NAME

Response: A list of all entities (with all the properties) in the specified collection (if no service-driven pagination imposed).

Example: http://demo.student.geocens.ca:8080/SWIOT_V0.9/Things

Usage 3: Address to an entity in a collection

Users can address to a specific entity in a collection by place the unique identifier of the entity between brace symbol “()” and put after the collection name. The service then returns the entity with all its properties.

URI Pattern: SERVICE_ROOT_URI/COLLECTION_NAME(KEY_OF_ENTITY)

Response: An entity (with all its properties) that holds the specified key in the collection.

Example: http://demo.student.geocens.ca:8080/SWIOT_V0.9/Things(1)

Usage 4: Address to a property of an entity

Users can address to a property of an entity by specifying the property name after the URI addressing to the entity. The service then returns the value of the specified property.

URI Pattern: SERVICE_ROOT_URI/COLLECTION_NAME(KEY_OF_ENTITY)/PROPERTY_NAME

Response: The specified property of an entity that holds the key in the collection.

Example: http://demo.student.geocens.ca:8080/SWIOT_V0.9/Observations(1)/Time

Usage 5: Address to a navigation property (link)

As the entities in different collections may hold some relationships, users can request the linked entities by addressing to a navigation property of an entity. The service then returns one or many entities that hold a certain relationship with the specified entity.

URI Pattern: SERVICE_ROOT_URI/COLLECTION_NAME(KEY_OF_ENTITY)/LINK_NAME

Response: One or many entities that holds a certain relationship with the specified entity.

Example: http://demo.student.geocens.ca:8080/SWIOT_V0.9/Datastreams(1)/Observations returns all the observations in the datastream.

Usage 6: Nested resource path

As users can use navigation properties to link from one collection to another, users can further extend the resource path with unique identifiers, properties, or links (i.e., Usage 3 to 5).

Example 1: http://demo.student.geocens.ca:8080/SWIOT_V0.9/Datastreams(1)/Observations(1) returns a specific observation in the datastream.

Example 2: http://demo.student.geocens.ca:8080/SWIOT_V0.9/Datastreams(1)/Observations(1)/Time turns the “Time” property of the specified observation in the datastream.

Example 3: http://demo.student.geocens.ca:8080/SWIOT_V0.9/Datastreams(1)/Observations(1)/FeatureOfInterest returns the feature of interest entity of the specified observation in the datastream.

2.2 Query Options

When users perform the READ action on resource(s), users can apply query options to further process the addressed resources. As the read action is performed through HTTP GET method, the query options are specified as key-value pairs after the question symbol "?" in the request URI. Currently, many of the query options defined in the OGC IoT RESTful API are similar to the query options in the OData. Therefore, some of the following explanations can be referenced to the OData specification.

NOTE: As our reference implementation hasn't supported all the functions proposed here, we use some examples from the OData test service (http://services.odata.org) to illustrate these functions. As OData might change their demo service, you might find some of the following OData examples not working. And some of the functions, there are no examples available, and these examples uses a pseudo-service root URL (e.g., http://example.com/)

2.2.1 $orderby

The $orderby query option is used to specify which properties are used to order the collection of entities identified by the resource path. This query option is only supported when the resource path identifies a collection of entries. The value of the $orderby query option contains a comma separated list of expressions whose primitive result values are used to sort the results. A special case of such an expression is a property path terminating on a primitive property.

The expression may include the suffix asc for ascending or desc for descending, separated from the property name by one or more spaces. If asc or desc is not specified, the service must order by the specified property in ascending order.

Null values come before non-null values when sorting in ascending order and after non-null values when sorting in descending order.

Example 1: http://services.odata.org/V3/OData/OData.svc/Products?$orderby=Rating returns all Products ordered by the Rating property in ascending order.

Example 2: http://services.odata.org/V3/OData/OData.svc/Products?$orderby=Rating,Category/Name desc returns all Products ordered by the Rating property in ascending order, then by the Name property of the linked Category entry in descending order.

2.2.2 $top

The $top query option specifies a non-negative integer that limits the number of entities returned within a collection. The service must return the number of available entities up to, but not exceeding, the specified value.

Usually, the $top query option is used with the $orderby query option. However, while no ordering semantics are mandated, to ensure repeatable results, a data service must always use the same semantics to obtain a full ordering across requests.

In addition, if the $top value exceeds the service-driven pagination limitation (i.e., the largest number of entities the service can return in a single response), the $top query option should be discarded and the pagination limitation should be imposed.

Example 1: http://services.odata.org/V3/OData/OData.svc/Products?$top=5 returns only the first five entities in the Products collection.

Example 2: http://services.odata.org/V3/OData/OData.svc/Products?$top=5&$orderby=Name desc returns the first five Product entries returned in descending order when sorted by the Name property.

2.2.3 $skip

The $skip query option specifies that the result must not include the first n entities, where n is a non-negative integer value specified by the $skip query option.

Usually, the $skip query option is used with the $orderby query option. However, while no ordering semantics are mandated, to ensure repeatable results, a data service must always use the same semantics to obtain a full ordering across requests.

Where $top and $skip are used together, the $skip must be applied before the $top, regardless of the order in which they appear in the request.

Example 1: http://services.odata.org/V3/OData/OData.svc/Products?$skip=5 returns Product entities starting with the sixth Product entity in the Products collection.

Example 2: http://services.odata.org/V3/OData/OData.svc/Products?$skip=2&$top=2&$orderby=Rating returns the third and fourth Product entities from the collection of all Product entities when the collection is sorted by the Rating property in ascending order.

2.2.4 $filter

A URI with a $filter query option identifies a subset of the entries from the collection of entries identified by the resource path of the URI. The subset is determined by selecting only the entries that satisfy the predicate expression specified by the $filter. The value of the $filter option is a Boolean expression.

The expression language that is used in $filter operators supports references to properties and literals. The literal values can be strings enclosed in single quotes, numbers and boolean values (true or false) or datetime values represented as datetime‘ISO 8601 time string’.

Example: http://services.odata.org/V3/OData/OData.svc/Products?$filter=Price lt 10.00 returns all Products whose Price is less than 10.00.

In addition, users may use the properties of linked entities in the $filter predicate. The following are examples of the possible uses of the $filter in the data model of the IoT RESTful service.

Example 1: ttp://iot-rest.example.com/Observations?$filter=ObservedProperty/UnitOfMeasurement eq ‘Celsius’ returns all Observations whose UnitOfMeasurement (a property of ObservedProperty) is ‘Celsius’.

Example 2: http://iot-rest.example.com/Things?$filter=Locations/Geometry st_within(POLYGON ((30 10, 10 20, 20 40, 40 40, 30 10))) returns Things whose current or past locations were in the polygon defined in the Well-Known Text (WKT).

Example 3: http://iot-rest.example.com/ Things?$filter=Sensors/Observations/FeatureOfInterest/ID eq ‘FOI_1’ and Sensors/Observations/Time ge datetime‘2010-06-01T00:00:00Z’ and Sensors/Observations/Time le datetime‘2010-07-01T00:00:00Z’ returns Things that made any observations on a feature of interest with a unique identifier equals to “FOI_1” in June 2010.

2.2.4.1 Built-in filter operations

The OGC IoT RESTful API supports a set of built-in filter operations, as described in the following table.


Operator Description Example
Logical Operators
eq Equal /Suppliers?$filter=Address/City eq 'Redmond'
ne Not equal /Suppliers?$filter=Address/City ne 'London'
gt Greater than /Products?$filter=Price gt 20
ge Greater than or equal /Products?$filter=Price ge 10
lt Less than /Products?$filter=Price lt 20
le Less than or equal /Products?$filter=Price le 100
and Logical and /Products?$filter=Price le 200 and Price gt 3.5
or Logical or /Products?$filter=Price le 3.5 or Price gt 200
not Logical negation /Products?$filter=not endswith(Description,'milk')
Arithmetic Operators
add Addition /Products?$filter=Price add 5 gt 10
sub Subtraction /Products?$filter=Price sub 5 gt 10
mul Multiplication /Products?$filter=Price mul 2 gt 2000
div Division /Products?$filter=Price div 2 gt 4
mod Modulo /Products?$filter=Price mod 2 eq 0
Grouping Operators
( ) Precedence grouping /Products?$filter=(Price sub 5) gt 10

2.2.4.2 Built-in query functions

IoT RESTful API supports a set of built-in functions that can be used within $filter operations. The following table lists the available functions. Most of these query functions are defined in the OData. However, in order to support more geospatial query functions, IoT RESTful API defines nine additional geospatial functions based on the spatial relationship between two geometry objects defined in the OGC Simple Feature Access specification (part 1, clause 6.1.2.3). The names of these nine functions start with a prefix “st_” as they are named in the OGC Simple Feature Access specification. In addition, for these eight functions, we define that users must specify input geometry in the Well-Known Text (WKT) format.


Function Example
String Functions
bool substringof substringof('Alfreds',CompanyName)
bool endswith endswith(CompanyName,'Futterkiste')
bool startswith startswith(CompanyName,'Alfr')
int length length(CompanyName) eq 19
int indexof indexof(CompanyName,'lfreds') eq 1
string substring substring(CompanyName,1) eq 'lfreds Futterkiste'
string tolower tolower(CompanyName) eq 'alfreds futterkiste'
string toupper toupper(CompanyName) eq 'ALFREDS FUTTERKISTE'
string trim trim(CompanyName) eq 'Alfreds Futterkiste'
string concat concat(concat(City,', '), Country) eq 'Berlin, Germany'
Date Functions
DateTime now StartTime ge now()
int year year(BirthDate) eq 0
int month month(BirthDate) eq 12
int day day(StartTime) eq 8
int hour hour(StartTime) eq 1
int minute minute(StartTime) eq 0
int second second(StartTime) eq 0
double fractionalseconds second(StartTime) eq 0
Date date date(StartTime) ne date(EndTime)
TimeOfDay time time(StartTime) le StartOfDay
int totaloffsetminutes totaloffsetminutes(StartTime) eq 60
DateTimeOffset mindatetime StartTime eq mindatetime()
DateTimeOffset maxdatetime EndTime eq maxdatetime()
Math Functions
double round round(Freight) eq 32
double floor floor(Freight) eq 32
double ceiling ceiling(Freight) eq 33
Type Functions
any cast cast(ShipCountry,Edm.String)
bool isof isof(NorthwindModel.Order)
bool isof isof(ShipCountry,Edm.String)
Geospatial Functions
double geo.distance geo.distance(CurrentPosition, TargetPosition)
double geo.length geo.length(DirectRoute)
bool geo.intersects geo.intersects(Position, TargetArea)
bool st_equals st_equals(POINT (30 10))
bool st_disjoint st_disjoint(POLYGON ((30 10, 10 20, 20 40, 40 40, 30 10)))
bool st_touches st_touches(LINESTRING (30 10, 10 30, 40 40))
bool st_within st_within(POLYGON ((30 10, 10 20, 20 40, 40 40, 30 10)))
bool st_overlaps st_overlaps(POLYGON ((30 10, 10 20, 20 40, 40 40, 30 10)))
bool st_crosses st_crosses(LINESTRING (30 10, 10 30, 40 40))
bool st_intersects st_intersects(LINESTRING (30 10, 10 30, 40 40))
bool st_contains st_contains(POINT (30 10))
bool st_relate st_relate(POLYGON ((30 10, 10 20, 20 40, 40 40, 30 10)), ‘T********’)

2.2.5 $expand

The $expand system query option indicates the related entities that must be represented inline. The value of the $expand query option must be a comma separated list of navigation property names. Additionally each navigation property can be followed by a forward slash and another navigation property to enable identifying a multi-level relationship.

Example 1: http://services.odata.org/V3/OData/OData.svc/Categories?$expand=Products returns the collection of Categories as well as each of the Products associated with each Category entity.

Example 2: http://services.odata.org/V3/OData/OData.svc/Categories?$expand=Products/Suppliers returns the collection of Categories, the Products associated with each Category, and the Suppliers associated with each Product.

Example 3: http://services.odata.org/V3/OData/OData.svc/Products?$expand=Category,Suppliers returns the collection of Products as well as the Category and Suppliers associated with each Product.

2.2.6 $select

A data service URI with a $select query option identifies the same set of entries as a URI without a $select query option; however, the value of $select specifies that a response from an IoT RESTful service should return a subset of the properties. The value of a $select query option is a comma-separated list of selection clauses. Each selection clause may be a property name (including navigation property names).

Example 1: http://services.odata.org/V3/OData/OData.svc/Products?$select=Price,Name returns only the Price and Name properties for each Product entity.

Example 2: http://service.odata.org/Categories?$select=Name,Products&$expand=Products/Supplier returns the Name properties of the Category entries, and all the properties of the entries identified by the Products and Suppliers navigation properties.

2.2.7 $count

The $count query option with a value of “true” specifies that the total count of entities within a collection matching the request must be returned along with the result. The $count system query option ignores any $top, $skip, or $expand query options, and returns the total count of results across all pages including only those results matching any specified $filter.

A $count with a value of “false” (or not specified) hints that the service should not return a count.

Example: http://services.odata.org/V3/OData/OData.svc/Products?$count=true returns, along with the results, the total number of products in the set.

3. $capabilities

This operation allows clients to retrieve the service metadata about a specific service instance. The $select is the only query option can be applied here. So users can only request for a partial of the capabilities document.

3.1 $capabilities Request

HTTP Method: GET

URI Pattern: SERVICE_ROOT_URI/$capabilities

Example: http://demo.student.geocens.ca:8080/SWIOT_V0.9/$capabilities

3.2 $capabilities Response

The capabilities document is a JSON encoded document. This document provides client with service metadata about a specific service instance. A service should use the capabilities document to advertise the supported functions and any constraints on using these functions. A service may also use the capabilities document to showcase the spatio-temporal coverage of the content. Finally, if a service provides any custom operations, the explanation of those operations should be included in the capabilities document as well.

The detail explanation about the capabilities document can be found in datamodel.html#capabilities.

4. Sensing Profile

The OGC IoT RESTful API sensing profile is based on the OGC SOS concept and designed specifically for the Internet of Things.

As most IoT devices are resource-constrained, the IoT RESTful API adopts the efficient RESTful web service style. That means the CRUD actions can be performed on Thing, Location, Datastream, Sensor, Observation, FeatureOfInterest, and ObservedProperty entity types. The following subsection explains the CRUD protocol for the Sensing Profile.

4.1 Resources in the Sensing Profile

The detail explanation about the resources in the Sensing Profile can be found here.

4.2 Create a Resource in Datastream Profile

To create an entity in a collection, the client sends a HTTP POST request to that collection's URL. The POST body must contain a single valid entity representation. In addition, the link between entities should be established upon creating an entity. Two use cases should be considered: (1) link to existing entities when creating an entity, and (2) create related entities when creating an entity. The requests for these two use cases are also described in the following subsection.

When users create resources in an IoT RESTful service, they need to follow some integrity constraints. For example, a Datastream entity must link to a Thing entity. So when a user wants to create a Datastream entity, he/she needs to either (1) create a linked Thing entity in the same request or (2) link to a already created Thing entity. The complete integrity constraints for creating resources are shown in the following table.

One special case is on creating an Observation entity that links to an FeatureOfInterest entity. Sometimes the FeatureOfInterest of an Observation is the Thing itself where the Observation is similar to an attribute of the Thing. In this cases, when a user creates an Observation entity, he/she can omit the link to a FeatureOfInterest entity in the POST body message. And if the service detects that there is no link to a FeatureOfInterst entity in a create-Observation entity request, the service must automatically create a FeatureOfInterest entity by interpolating the geometry property from the locations of the Thing entity.


Scenario Integrity Constraints
Create a Thing entity -
Create a Location entity Link to a Thing entity.
Create a Datastream entity Link to a Thing entity.
Link to an ObservedProperty entity.
Create a Sensor entity Link to a Datastream entity.
Create an ObservedProperty entity -
Create an Observation entity Link to a Datastream entity.
Link to a FeatureOfInterest entity.
(If no link specified, the service must create a FeatureOfInterest entity from the information of the Thing and Location entities.)
Create a FeatureOfInterest entity -
Create a TaskingCapability entity Link to a Thing entity.
Create an Actuator entity Link to a TaskingCapability entity.
Create a Task entity Link to a TaskingCapability entity.

More examples about the POST body messages for different resources can be found in the Interactive SDK.

4.2.1 Request

HTTP Method: POST

URI Pattern: SERVICE_ROOT_URI/COLLECTION_NAME

Header: Content-Type: application/json

Message Body: A single valid entity representation for the specified collection.

Example: Create a Thing entity

POST /SWIOT_V0.9/Things HTTP/1.1
Host: demo.student.geocens.ca:8080
Content-Type: application/json

{
  "Description":"This thing is an oven."
}

4.2.2 Response

Upon successfully creating an entity, the service response must contain a Location header that contains the URL of the created entity. Upon successful completion the service must respond with 201 Created. Regarding all the HTTP status code, please refer to the HTTP Status Code section.

4.3 Read a Resource in Datastream Profile

4.3.1 Request

HTTP Method: GET

URI Pattern: Refer to the URIComponents section, including resource path and query options

4.3.2 Response

The detail explanation about the encodings of resources in the datastream profile can be found in datamodel.html#DatastreamProfile.

Upon successfully retrieve resources, the service service must respond with 200 OK. Regarding all the HTTP status code, please refer to the HTTP Status Code section.

4.4 Update a Resource in Datastream Profile

4.4.1 Request

Services should support HTTP PATCH as the preferred means of updating an entity. HTTP PATCH provides more resiliencies between clients and services by directly modifying only those values specified by the client.

The semantics of PATCH, as defined in [RFC5789], are to merge the content in the request payload with the entity’s current state, applying the update only to those components specified in the request body. Collection properties and primitive properties provided in the payload must replace the value of the corresponding property in the entity or complex type. Missing properties of the containing entity or complex property, including dynamic properties, must not be directly altered.

Services may additionally support HTTP PUT, but should be aware of the potential for data-loss in round-tripping properties that the client may not know about in advance. Services that support HTTP PUT must replace all property values with those specified in the request body. Missing properties must be set to their default values. Missing optional properties must be removed.

Unique identifiers and other non-updatable properties may be omitted from the request. If the request contains a value for an identifier or other non-updatable property, the service must ignore that value when applying the update.

The entity must not contain related entities as inline content. Additional values for properties beyond those specified in the IoT RESTful data model should not be sent in the request body. The service should consider such a request malformed.

HTTP Method: PATCH or PUT

URI Pattern: An URI addressing to a single entity.

Header: Content-Type: application/json

Message Body: A single entity representation including a subset of properties for the specified collection.

Example: Update the Thing with key equals to 1

PATCH /SWIOT_V0.9/Things(1) HTTP1.1
Host: demo.student.geocens.ca:8080
Content-Type: application/json

{
  "Description":"This thing is an oven own by the Toms."
}

4.4.2 Response

On success, the response must be a valid success response. In addition, when the client sends an update request to a valid URL where an entity does not exist, the service must fail the request.

Upon successful completion, the service service must respond with 200 OK or 204 No Content. Regarding all the HTTP status code, please refer to the HTTP Status Code section.

4.5 Delete a Resource in Datastream Profile

4.5.1 Request

To delete an existing entity, the client sends a HTTP DELETE request to that entity's edit URL. The request body should be empty.

HTTP Method: DELETE

URI Pattern: An URI addressing to a single entity.

Example: Delete the Thing with unique identifier equals to 1

HTTP DELETE http://demo.student.geocens.ca:8080/SWIOT_V0.9/Things(1)

Services must implicitly remove relations to and from an entity when deleting it; clients need not delete the relations explicitly.

Services should implicitly delete related entities if required by the following integrity constraints.


Scenario Integrity Constraints
Delete a Thing entity Delete all the Datastream entities linked to the Thing entity.
Delete all the TaskingCapability entities linked to the Thing entity.
Delete the Location entities that will not link to any entities after deletion.
Delete a Location entity -
Delete a Datastream entity Delete the Sensor entity linked to the Datastream entity.
Delete all the Observation entities linked to the Datastream entity.
Delete a Sensor entity -
Delete an ObservedProperty entity Delete all the Datastream entities linked to the ObservedProperty entity.
Delete an Observation entity -
Delete a FeatureOfInterest entity Delete all the Observation entities linked to the FeatureOfInterest entity.
Delete a TaskingCapability entity Delete the Actuator entity linked to the TaskingCapability entity.
Delete an Actuator entity -
Delete a Task entity -

4.5.2 Response

On successful completion of the delete, the response must be 200 OK, 202 Accepted, or 204 No Content and contain an empty body. Regarding all the HTTP status code, please refer to the HTTP Status Code section.

5. TaskingCapability Profile

The IoT RESTful TaskingCapability profile is mainly for users to control actuators through a unified web service interface. There are two major parts in the TaskingCapability profile. The first part is to convey the acceptable parameters of an actuator and allow users to submit controlling tasks through a RESTful interface. The second part in the TaskingCapability profile is to allow IoT RESTful services to communicate with actuators that are attached to things. Therefore, the following two functionalities should be supported: (1) data producers describing and registering the protocol to communicate with the device; and (2) IoT RESTful services creating requests and understanding response with the registered device protocol.

The potential workflow would be (1) a thing (a data producer) creates itself and an actuator attached to it in an IoT RESTful service, (2) a user retrieves the capabilities document from the IoT RESTful service, (3) the user retrieves the actuator resource and understands the acceptable parameters of the actuator, (4) with the parameter information, the user creates a task entity (like creating other resources in the IoT RESTful servie) with specified input values for parameters and the time that the user wants this task to be executed, (5) after the user creates the task in the IoT RESTful service, the IoT RESTful service creates a request in the device protocol based on user’s input value and sends the request to the thing at the user-specified time, (6) the thing then executes the request and returns a response to the IoT RESTful service in the device protocol, and finally, (7) the IoT RESTful service parses the response and updates the status property in the user-created task entity.

To sum up, the concept of the IoT RESTful TaskingCapability profile is to provide a RESTful interface for users to submit tasks to control actuators. As IoT RESTful services handle the communication in device protocols, users can easily control Internet of Things with a simple and unified RESTful interface.

5.1 Resources in Actuator Profile

The detail explanation about the resources in the taskingCapability profile can be found in datamodel.html#TaskingCapabilityProfile.

5.2 Create a Resource in Actuator Profile

The protocol of creating a resource in the taskingCapability profile is similar to that in the datastream profile (api.html#Create_DatastreamProfile). Only when creating a taskingCapability entity, the request needs to specify the device protocol (datamodel.html#TaskingCapability), which is not visible to users in the Read response.

Example: Create a TaskingCapability entity

POST /SWIOT_V0.9/TaskingCapabilities HTTP/1.1
Host: demo.student.geocens.ca:8080
Content-Type: application/json

{
  "Thing":{"ID":1},
  "Description":"this is TaskingCapability 1",
  "Parameters":[
  {
    "ParameterID":"paramOn",
    "Description":"on",
    "Use":"mandatory",
    "Definition":
    {
      "InputType":"Integer",
      "UnitOfMeasurement":"brightness degrees",
      "AllowedValues":[{"Min":"10","Max":"15"}]
    }
  }],
  "Protocols":[
  {
    "HTTPMethod":"POST",
    "AbsoluteResourcePath":"http://path.com",
    "MessageBody":"lamp-id=1&on={paramOn}"
  }],
  "Actuator":
  {
    "Metadata":"This is an actuator"
  }
}

In addition, the behavior of creating a task entity is the same as submitting a tasking job to the thing. The IoT RESTful service will compose a request in the device protocol (from the protocol property in the TaskingCapability entity), and send the request at the specified time point. While composing a request in a device protocol, the values of inputs in the task entity will be used to replace the "{ParameterID}" in the device protocol. For instance, the following example requires an IoT RESTful service to replace "{paramOn}" string in the device protocol with the input value 200. Therefore, with the above taskingCapability entity, the IoT RESTful service will send a HTTP POST reqeust to http://path.com with a messageBody as "lamp-id=1&on=200" at 2013-04-18T16:15:00-0700.

When creating a task entity, if the value of Time property is in the past, the task should be sent to the thing immediately.

Example: Create a Task entity

POST /SWIOT_V0.9/Tasks HTTP/1.1
Host: demo.student.geocens.ca:8080
Content-Type: application/json

{
  "TaskingCapability":{"ID":5},
  "Inputs":[
  {
    "ParameterID":"paramOn",
    "Value":200
  }],
  "Time":"2013-04-18T16:15:00-0700"
}

Upon successfully creating an entity, the service response must contain a Location header that contains the URL of the created entity. Upon successful completion the service must respond with 201 Created. Regarding all the HTTP status code, please refer to the HTTP Status Code section.

5.3 Read a Resource in Actuator Profile

The protocol of reading a resource in the TaskingCapability profile is the same as that in the Datastream profile (api.html#Read_DatastreamProfile). The only exception is that when reading a TaskingCapability entity, the device protocol is not visible to users in the response.

The detail explanation about the encodings of resources in the TaskingCapability profile can be found in datamodel.html#TaskingCapabilityProfile.

Upon successfully retrieve resources, the service service must respond with 200 OK. Regarding all the HTTP status code, please refer to the HTTP Status Code section.

5.4 Update a Resource in Actuator Profile

The protocol of updating a resource in the TaskingCapability profile is the same as that in the Datastream profile (api.html#Update_DatastreamProfile). Only the Status property in a Task entity is a service-controlled property and cannot be updated by users. IoT RESTful service updates the status based on responses from the thing.

Upon successful completion, the service service must respond with 200 OK or 204 No Content. Regarding all the HTTP status code, please refer to the HTTP Status Code section.

5.5 Delete a Resource in Actuator Profile

The protocol of deleting a resource in the TaskingCapability profile is the same as that in the Datastream profile (api.html#Delete_DatastreamProfile). When deleting a Task entity that hasn't been triggered, the service must remove the corresponding thread of sending task as well.

On successful completion of the delete, the response must be 200 OK, 202 Accepted, or 204 No Content and contain an empty body. Regarding all the HTTP status code, please refer to the HTTP Status Code section.

6. Batch Processing

The IoT RESTful service interface provides interfaces for users to perform CRUD actions on resources through different HTTP methods. However, as IoT devices are usually resource-constrained, handling a large number of communications may be not practical. This section describes how an IoT RESTful service can optionally support executing multiple operations sent in a single HTTP request through the use of batch processing. This section covers both how batch operations are represented and processed.

6.1 Request

A batch request is represented as a Multipart MIME v1.0 message [RFC2046], a standard format allowing the representation of multiple parts, each of which may have a different content type, within a single request.

6.1.1 Headers

Batch requests allow grouping multiple operations, as described in DatastreamProfile and TaskingCapabilityProfile, into a single HTTP request payload.

Batch Requests are submitted as a single HTTP POST request to the $batch endpoint of a service. The batch request must contain a Content-Type header specifying a content type of "multipart/mixed" and a boundary specification. The example below shows a GUID as a boundary and "OData/OData.svc"for the URI of the service. is defined in the Batch Request Body section below.

POST OData/OData.svc/$batch HTTP/1.1
Host: services.odata.org
DataServiceVersion: 1.0
MaxDataServiceVersion: 2.0
Content-Type: multipart/mixed; boundary=batch(36522ad7-fc75-4b56-8c71-56071383e77b)

BATCH_REQUEST_BODY

The batch request boundary must be quoted if it contains any of the following special characters:

( ) < > @ , ; : / " [ ] ? =

In addition to the Content-Type header, the Batch request may contain DataServiceVersion headers or other HTTP Headers which apply to the entire Batch Request as appropriate. In the example above, DataServiceVersion has a value of 1.0 representing the version of the OData specification used to generate the request, and MaxDataServiceVersion has a value of 2.0 representing the maximum response version the client is prepared to accept.

6.1.2 Message Body

The body of a Batch Request is made up of an ordered series of retrieve operations (as described in [OData-Operations] ) and/or ChangeSets. A ChangeSet is an atomic unit of work that is made up of an unordered group of one or more of the insert, update or delete operations described in < a href="/developers/protocols/operations">[OData:Operations]. ChangeSets cannot contain retrieve requests and cannot be nested (i.e. a ChangeSet cannot contain a ChangeSet).

In the Batch request body, each retrieve request and ChangeSet is represented as a distinct MIME part and is separated by the boundary marker defined in the Content-Type header of the request. The contents of the MIME part which represents a ChangeSet is itself a multipart MIME document with one part for each operation that makes up the ChangeSet.

Each MIME part representing a retrieve request or ChangeSet within the Batch includes both Content-Type and Content-Transfer-Encoding MIME headers as seen in the examples below. The batch request boundary is the name specified in the Content-Type Header for the batch.

The example below shows a sample batch request that contains the following operations in the order listed:

  • Retrieve
  • A Change Set that contains the following requests:
    • Insert
    • Update
  • A second retrieve request

Note: In the example, request bodies are excluded in favor of English descriptions inside '<>' brackets to simplify the example.

POST OData/OData.svc/$batch HTTP/1.1
Host: services.odata.org
Content-Type: multipart/mixed; boundary=batch(36522ad7-fc75-4b56-8c71-56071383e77b)

--batch_36522ad7-fc75-4b56-8c71-56071383e77b
Content-Type: application/http 
Content-Transfer-Encoding:binary

GET /service/Customers('ALFKI') HTTP/1.1
Host: host

--batch_36522ad7-fc75-4b56-8c71-56071383e77b 
Content-Type: multipart/mixed; boundary=changeset_77162fcd-b8da-41ac-a9f8-9357efbbd621 
Content-Length: ###       

--changeset(77162fcd-b8da-41ac-a9f8-9357efbbd621) 
Content-Type: application/http 
Content-Transfer-Encoding: binary 

POST /service/Customers HTTP/1.1 
Host: host  
Content-Type: application/atom+xml;type=entry 
Content-Length: ### 

 

--changeset(77162fcd-b8da-41ac-a9f8-9357efbbd621) 
Content-Type: application/http 
Content-Transfer-Encoding:binary 

PUT /service/Customers('ALFKI') HTTP/1.1 
Host: host 
Content-Type: application/json 
If-Match: xxxxx 
Content-Length: ### 

 

--changeset(77162fcd-b8da-41ac-a9f8-9357efbbd621)-- 

--batch(36522ad7-fc75-4b56-8c71-56071383e77b) 
Content-Type: application/http 
Content-Transfer-Encoding:binary 

GET service/Products HTTP/1.1 
Host: host 

--batch(36522ad7-fc75-4b56-8c71-56071383e77b)--

If a MIME part representing an Insert request within a ChangeSet includes a Content-ID header, then the new entity may be referenced by subsequent requests within the same ChangeSet by referring to the Content-ID value prefixed with a "$" character. When used in this way, $ acts as an alias for the Resource Path that identifies the new entity.

6.2 Process a Batch Request

Requests within a batch are evaluated according to the same semantics used when the request appears outside of the context of a batch.

The order of ChangeSets and retrieve requests within a Batch request is significant as it states the order in which the service processes the components of the Batch. The order of requests within a ChangeSet is not significant such that a service may process the requests within a ChangeSet in any order.

All operations in a ChangeSet represent a single change unit so the server must successfully process and apply all the requests in the ChangeSet or else apply none of the requests in the ChangeSet. It is up to the service to define rollback semantics to undo any requests within a ChangeSet that may have been applied before another request in that same ChangeSet failed and thereby honor this all-or-nothing requirement.

If the set of HTTP Request headers of a Batch request are valid (the Content-Type is set to multipart/mixed, etc.) the server returns a 202 Accepted HTTP response code to indicate that the request has been accepted for processing, but that the processing has not yet been completed. The requests within the Batch request body may subsequently fail or be malformed; however, this mechanism enables clients of a Batch implementation to stream the results of a Batch request without having to first wait for all requests to be processed.

If the service receives a Batch request with an invalid set of headers it returns a 4xx response code and no further processing of the batch is performed.

6.3 Response

6.3.1 Headers

The batch response, as shown in the example below, must contain a Content-Type header specifying a content type of multipart/mixed and a batch boundary specification which may be different than the batch boundary that was used in the corresponding request.

HTTP/1.1 202 Accepted
DataServiceVersion: 1.0
Content-Length: 1254
Content-Type: multipart/mixed; boundary=batch(36522ad7-fc75-4b56-8c71-56071383e77b)
						

6.3.2 Message Body

Within the body of the batch response is a response for each retrieve request and ChangeSet that was in the associated Batch request. The order of responses in the response body must match the order of requests in the Batch request. Each response includes a Content-Type header with a value of "application/http", and a Content-Transfer-Encoding MIME header with a value of "binary".

A response to a retrieve request is formatted exactly as it would have appeared outside of a batch as described in [OData-Operations] .

The body of a ChangeSet response is either a response for all the successfully processed change request within the ChangeSet, formatted exactly as it would have appeared outside of a batch, as described in [OData-Operations] , or a single response indicating a failure of the entire ChangeSet, as described in [OData-Operations].

For example, referencing the batch request in section 2.2, assume all the requests except the final retrieve request succeed. In this case the Batch response body would be as shown in the following example.

HTTP/1.1 202 Accepted
DataServiceVersion: 1.0
Content-Length: ####
Content-Type: multipart/mixed; boundary=batch(36522ad7-fc75-4b56-8c71-56071383e77b)

--batch(36522ad7-fc75-4b56-8c71-56071383e77b)
Content-Type: application/http
Content-Transfer-Encoding: binary

HTTP/1.1 200 Ok
Content-Type: application/atom+xml;type=entry
Content-Length: ###



--batch(36522ad7-fc75-4b56-8c71-56071383e77b)
Content-Type: multipart/mixed; boundary=changeset(77162fcd-b8da-41ac-a9f8-9357efbbd621)
Content-Length: ###      

--changeset(77162fcd-b8da-41ac-a9f8-9357efbbd621)
Content-Type: application/http
Content-Transfer-Encoding: binary

HTTP/1.1 201 Created
Content-Type: application/atom+xml;type=entry
Location: http://host/service.svc/Customer('POIUY')
Content-Length: ###



--changeset(77162fcd-b8da-41ac-a9f8-9357efbbd621)
Content-Type: application/http
Content-Transfer-Encoding: binary

HTTP/1.1 204 No Content
Host: host

--changeset(77162fcd-b8da-41ac-a9f8-9357efbbd621)--

--batch(36522ad7-fc75-4b56-8c71-56071383e77b)
Content-Type: application/http
Content-Transfer-Encoding: binary

HTTP/1.1 404 Not Found
Content-Type: application/xml
Content-Length: ###


--batch(36522ad7-fc75-4b56-8c71-56071383e77b)--

7. HTTP Status Code

All status codes used in the IoT RESTful API follow the standard HTTP status codes. A high-level explanation of the status codes is as follows:


HTTP Status Code Description
2xx Success
3xx Redirection
4xx Client-side Error
5xx Server-side Error