REST implementation
This section describes the aspects common to all REST-based interfaces of Cumulocity IoT. The interfaces are based on the Hypertext Transfer Protocol 1.1 using HTTPS.
This section describes the aspects common to all REST-based interfaces of Cumulocity IoT. The interfaces are based on the Hypertext Transfer Protocol 1.1 using HTTPS.
All requests need to be authenticated. There are two ways to do that. First is
to include the HTTP “Authorization” header. The second is OAuth2 authentication code grant. Both are described below.
For the Authorization header method the format is:
Authorization: Basic <<Base64 encoded credentials>>
An example can be found in the Wikipedia entry.
For OAuth authentication the format is:
Authorization: Bearer <<Base64 encoded access token>>
Cumulocity IoT uses the URL in the “Host” header to determine the tenant to authenticate against. Alternatively, you can pass the tenant’s ID as part of the “Authorization” header in the following form:
<<tenant ID>>/<<user name>>:<<password>>
For details on the tenant ID, refer to Tenants > Tenant ID and tenant domain.
Cumulocity IoT supports two factor authentication. If it is enabled, the two factor authentication token is sent in header:
TFAToken:<<tfa-token>>
If the token expires and requires renewal, the backend sends a response header:
TFATokenExpired:TFATokenExpired
Cumulocity IoT supports JWT token authentication. The HTTP header must include:
Authorization: Bearer <<Base64 encoded JWT token>>
The JWT token must be signed using RSA signature with SHA-256 (RS256). The minimal RSA key size is 512 bit. You can generate an example key here.
You must upload your public key to the tenant options to the “token.publicKey” category.
Example:
POST /tenant/options
Host: ...
Authorization: Basic ...
Content-Type: application/vnd.com.nsn.cumulocity.option+json;ver=...
Accept: application/vnd.com.nsn.cumulocity.option+json;ver=...
{
"category": "token.publicKey",
"key": "myPubKey",
"value": "..."
}
The “key” is an identifier of the public key, which will be referenced in the JWT token header, and the “value” is the public key in PEM format.
Now you can generate the JWT token and sign it with th ematching private key. For example you can do it here.
Token format:
{
"typ": "JWT",
"alg": "RS256",
"kid": "myPubKey"
}
{
"iss": "cumulocity",
"aud": "myTenant",
"sub": "username",
"nbf": 1515678716,
"exp": 1516629116
}
If tenant/username don’t match or the token is expired or the signature is invalid then a 401 error will be returned.
The login with OAuth requires a correct configuration on the Cumulocity IoT side. With the configuration, an additional button is available on the Login page. After clicking the button, the user is redirected to authenticate with the configured authorization server. On successful login, the user is redirected to Cumulocity IoT.
Authentication details are exchanged using cookies. There are two parts to it, the first is the authentication cookie that is handled automatically by the Cumulocity IoT platform. The second is the XSRF-TOKEN cookie. When a client receives the cookie, it should take the value and put it in the X-XSRF-TOKEN request header in all subsequent requests.
The flow of authenticating with OAuth authentication code grant is as follows:
The first request executed by the browser is:
POST /tenant/loginOptions
Host: ...
Content-Type: application/vnd.com.nsn.cumulocity.loginOptionCollection+json;ver=...
Accept: application/vnd.com.nsn.cumulocity.loginOptionCollection+json;ver=...
Response:
{
"loginOptions": [
{
"buttonName": "Login with oauth",
"grantType": "AUTHORIZATION_CODE",
"initRequest": "https://TENANT.cumulocity.com/tenant/oauth?response_type=code&tenant_id=TENANT",
"self": "http://TENANT.cumulocity.com/tenant/loginOptions/oauth2",
"type": "oauth2"
},
{
"self": "http://dev-d.cumulocity.com/tenant/loginOptions/basic",
"type": "basic"
}
],
"self": "http://dev-d.cumulocity.com/tenant/loginOptions/"
}
Here we have two login options, one with basic and the other with OAuth2. If a user decides to login with OAuth, the browser must invoke the request provided in the initRequest parameter.
The initRequest initiates the redirect, in which the user is prompted for credentials. After successful login, the user is redirected back to the browser, where it must capture the code request parameter. Then the request to exchange the code for the token is as follows:
POST /tenant/oauth?grant_type=authorization_code&code=<<code>>
Host: ...
A successful response will have no body but the following response headers:
Set-Cookie: authorization=<<token>>;
Set-Cookie: XSRF-TOKEN=<<xsrfToken>>;
Authorization cookie is valid for 2 weeks.
Cumulocity IoT uses a so-called “application key” to distinguish requests coming from devices and traffic from applications. If you write an application, pass the following header as part of all requests:
X-Cumulocity-Application-Key: <<application key>>
For example, if you registered your application in the Cumulocity IoT administration application with the key “myapp”, pass
X-Cumulocity-Application-Key: myapp
This makes your application subscribable and billable. If you implement a device, do not pass the key.
Make sure that you pass the key in all requests coming from an application. If you leave out the key, the request will be considered a device request and the corresponding device will be marked as “available”.
If you use an HTTP client that can only perform GET and POST methods in HTTP, you can emulate the other methods through an additional “X-HTTP-METHOD” header. Simply issue a POST request and add the header, specifying the actual REST method to be executed. For example, to emulate the “PUT” (modify) method, you can use:
POST ...
X-HTTP-METHOD: PUT
Every update request (PUT, POST, DELETE) executes with a so-called processing mode. The processing modes are as follows:
Processing mode | Description |
---|---|
Persistent (default) | All updates will be send both to the Cumulocity IoT database and to real-time processing. |
Transient | Updates will be sent only to real-time processing. As part of real-time processing, the user can decide case by case through scripts whether updates should be stored to the database or not. |
Quiescent | The QUIESCENT processing mode behave like the PERSISTENT processing mode with the exception that no real-time notifications will be sent. Currently, the QUIESCENT processing mode is applicable for measurements and events only. |
CEP | The CEP processing mode behaves like the TRANSIENT processing mode with the exception that no real-time notifications will be sent. Currently, the CEP processing mode is applicable for measurements and events only. |
To explicitly control the processing mode of an update request, an “X-Cumulocity-Processing-Mode” header can be used with a value of either “PERSISTENT”, “TRANSIENT”, “QUIESCENT” or “CEP”:
X-Cumulocity-Processing-Mode: TRANSIENT
All requests issued to Cumulocity IoT are subject to authorization. To determine the required permissions, see the “Required role” entries in the reference documentation for the individual requests. To learn more about the different permissions and the concept of ownership in Cumulocity IoT, see “Managing permissions and ownership” in the Section “Security aspects”.
Each type of data is associated with an own media type. The general format of media types is
application/vnd.com.nsn.cumulocity.<<type>>+json;ver=<<version>>;charset=UTF-8
Each media type contains a parameter “ver” indicating the version of the type. At the time of writing, the latest version is “0.9”. The complete media type names are given in the respective sections of the reference guide. As an example, the media type for an error message in the current version is
application/vnd.com.nsn.cumulocity.error+json;ver=0.9;charset=UTF-8
Media types are used in HTTP “Content-Type” and “Accept” headers. If you specify an “Accept” header in a POST or PUT request, the response will contain the newly created or updated object. If you do not specify the header, the response body will be empty.
If a media type without “ver” parameter is given, the oldest available version will be returned by the server. If the accept header contains the same media type in multiple versions the server will return a representation in the latest supported version.
Data exchanged with Cumulocity IoT in HTTP requests and responses is encoded in JSON format and UTF-8 character encoding. Timestamps and dates are accepted and emitted by Cumulocity IoT in ISO 8601 format:
Date: YYYY-MM-DD
Time: hh:mm:ss±hh:mm
Timestamp: YYYY-MM-DDThh:mm:ss±hh:mm
To avoid ambiguity, all times and timestamps must include timezone information. Please take into account that the plus character “+” must be encoded as “%2B”.
Cumulocity IoT APIs are restricted by following data types:
Type | Description | Size | Possible values |
---|---|---|---|
boolean | true or false | 1 bit | true, false |
int | two’s complement integer | 32 bit | from -2,147,483,648 to +2,147,483,647 |
long | two’s complement integer | 64 bit | from -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 |
float | IEEE 754 floating point | 32 bit | from 1.40129846432481707e-45 to 3.40282346638528860e+38 (positive or negative) |
double | IEEE 754 floating point | 64 bit | from 4.94065645841246544e-324d to 1.79769313486231570e+308d (positive or negative) |
string | represents character strings | - | maximum 2,147,483,647 characters |
datetime | date or time or timestamp | - | ISO 8601 datetime |
object | A structure of key and value pairs | - | JSON objects, refer to w3schools > JS JSON > JSON Objects |
array | A list of values that have the same type | - | JSON arrays, refer to w3schools > JS JSON > JSON Arrays |
In error cases, Cumulocity IoT returns standard HTTP response codes as described in RFC2616. A Client should not only be able to handle individual codes but classes of codes as well (e.g., 4xx). The response body can contain more information about the error, see the error media type definition below. General error interpretations are:
Code | Name | Description |
---|---|---|
400 | Bad Request | The request could not be understood by the server due to malformed syntax. The client SHOULD NOT repeat the request without modifications. |
401 | Unauthorized | Authentication has failed, or credentials were required but not provided. |
403 | Forbidden | You are not authorized to access the API. |
404 | Not Found | Resource not found at given location. |
405 | Method not allowed | The employed HTTP method cannot be used on this resource (e.g., using “POST” on a read-only resource). |
409 | Update Conflict | Conflict on resource update, entity was changed in the meantime. |
409 | Duplicate | The entity already exists in the data source. |
413 | Execution timeout, operation will be abandoned | Query had been running too long and was timed out. |
422 | Invalid Data | General error with entity data format. |
422 | Non Unique Result | Resource constraints error. Non-unique result from the query. |
422 | Unprocessable entity | Resource cannot be processed. |
429 | Requests rate exceeds the limit | If the request rate limit per second is exceeded, the requests are delayed and kept in queue until the queue number limit is exceeded in which case the request is terminated with an error. |
500 | Internal Server Error | An internal error in the software system has occurred and the request could not be processed. |
503 | Service Unavailable | The service is currently not available. This may be caused by an overloaded instance or it is down for maintenance. Please try it again in a few minutes. |
The semantics described in the HTTP specification are used:
If a PUT request only contains parts of a resource, so called “fragments”, only those parts are updated. To remove a fragment, use a PUT request with a null value for the fragment. PUT cannot update sub-resources that are identified by a separate URI.
Clients should not make assumptions on the layout of URIs used in requests, but construct URIs from previously returned URIs or URI templates. The root interface provides the entry point for clients, see below.
URI templates contain placeholders in curly braces, which need to be filled by the client to produce a URI. As an example, see the following excerpt from the event API response:
HTTP/1.1 200 OK
Content-Type: application/vnd.com.nsn.cumulocity.eventApi+json;...
Content-Length: ...
{
...
"events" : { "self" : "http://..." },
"eventsForSourceAndType" : "http://...?type={type}&source={source}"
...
}
The client would need to fill the “type” and “source” placeholders with the desired type and source devices of the events to be returned. The meaning of these placeholders is documented in the respective interface descriptions in the reference guide.
In general, Cumulocity IoT REST resources are modelled according to the following pattern:
Collection resources support paging of data to avoid passing huge data volumes in one block from client to server. GET requests to collections accept two query parameters: “pageSize” indicates how many entries of the collection should be returned. By default, 5 entries are returned. The upper limit for one page is currently 2,000 documents, any larger requested page size is trimmed to the upper limit. “currentPage” defines the slice of data to be returned, starting with “1”. By default, the first page is returned.
For convenience, collection resources provide a “next” and “prev” links to retrieve the next resp. the previous page of the results. This is an example response for managed object collections:
{
"self" : "...",
"managedObjects" : [
...
],
"statistics" : {
"totalPages" : 7,
"pageSize" : 5,
"currentPage" : 2
},
"prev" : "http://...?pageSize=5&Page=1",
"next" : "http://...?pageSize=5&Page=3"
}
Please note that the totalPages property can be expensive to compute, hence it is not returned by default for range queries. To include totalPages in the result, add the query parameter “withTotalPages=true”.
Info: If inventory roles are applied to a user, a query by the user may return less than pageSize results even if there are more results in total.
If a user does not have a global role for reading data from the API resource but rather has inventory roles for reading only particular documents there are some differences in query result paging:
In some circumstances the response may contain less than pageSize elements though there is more data in the database accessible for the user.
In some circumstances “next” and “prev” links may appear in the response though there is no more data in the database accessible for the user.
The property “currentPage” of the response does not contain the page number but the offset of the next element not yet processed by the querying mechanism.
The query parameter “withTotalPages=true” has no effect and value of “totalPages” property is always null.
The above behavior results from the fact that the querying mechanism is iterating maximally over 10 * max(pageSize, 100) documents per request and stops though the full page of data accessible for the user could not be collected. When the next page is requested the querying mechanism starts the iteration where it finished the previous time.
Use the following parameters to obtain data for the specified time interval:
Example formats:
dateTo=2019-04-20
dateTo=2019-04-20T08:30:00.000Z
Parameters are optional. Values provided with those parameters are inclusive.
To discover the URIs to the various interfaces of Cumulocity IoT, a “root” interface is provided. This root interface aggregates all the underlying API resources and is available through http://<<yourURL>>.cumulocity.com/platform/". For more information on the different API resources, please consult the respective API sections of this reference guide.
Name | Type | Occurs | Description |
---|---|---|---|
self | URI | 1 | Link to this Resource |
inventory | InventoryAPI | 1 | See inventory interface. |
identity | IdentityAPI | 1 | See identity interface. |
event | EventAPI | 1 | See event interface. |
measurement | MeasurementAPI | 1 | See measurement interface. |
audit | AuditAPI | 1 | See auditing interface. |
alarm | AlarmAPI | 1 | See alarm interface. |
user | UserAPI | 1 | See user interface. |
deviceControl | DeviceControlAPI | 1 | See device control interface. |
Response body: application/vnd.com.nsn.cumulocity.platformApi+json
Example response:
HTTP/1.1 200 OK
Content-Type: application/vnd.com.nsn.cumulocity.platformApi+json;...
Content-Length: ...
{
"self" : "<<URL to the platform API resource>>",
"event" : {
"self" : "<<URL to the event API resource>>",
"events" : { "self" : "<<URL to event collection resource>>" },
"eventsForSourceAndType" : "<<URL to event collection resource>>?type={type}&source={source}"
...
},
"inventory" : {
...
},
...
}
The error type provides further information on the reason of a failed request.
Name | Type | Occurs | Description |
---|---|---|---|
error | string | 1 | Error type formatted as “<<resource type>>/<<error name>>". For example, an object not found in the inventory is reported as “inventory/notFound”. |
message | string | 1 | Short text description of the error |
info | string | 1 | URL to an error description on the Internet. |
details | Error details | 1 | Error details. Only available in DEBUG mode. |
Error details are provided in the following structure:
Name | Type | Occurs | Description |
---|---|---|---|
expectionClass | string | 1 | Class name of an exception that caused this error. |
exceptionMessage | string | 1 | Exception message content. |
expectionStackTrace | string | 1 | Strack trace of the exception. |
- | - | - | Further diagnostic information depending on error type. |
Paging statistics for collection resources are provided in the following format:
Name | Type | Occurs | Description |
---|---|---|---|
totalPages | int | 1 | The total number of paginated results (pages). |
pageSize | int | 1 | Maximum number of records contained in this query. |
currentPage | int | 1 | The current returned page within the full result set, starting at “1”. |
Info: The
totalPages
property is not returned by default in the response. To include it, add the query parameterwithTotalPages=true
.