Overview

This section describes specific aspects of developing microservices using the REST interface.

Cumulocity IoT employs REST for all external communication. Regardless whether the communication originates from IoT devices, from web applications or from back-office IT systems, the communication protocol is always REST.

REST is a very simple and secure protocol based on HTTP(S) and TCP. It is today the de-facto Internet standard supported by all networked programming environments ranging from very simple devices up to large-scale IT. One of the many books introducing REST is RESTful Web Services.

With this API description you will learn how to use Cumulocity IoT’s REST interfaces to develop microservice applications on top of the Cumulocity IoT platform.

The description is closely linked to the Cumulocity IoT OpenAPI Specification, which describes each interface in detail. Relevant sections in the Cumulocity IoT OpenAPI Specification are in particular:

If you develop applications using Java, check Microservice SDK for Java for even more convenient access to Cumulocity IoT’s functionality.

For further information on integrating devices using REST, refer to Device integration using REST in Device integration.

Using the REST interfaces

Nowadays, most programming environments have particular support for REST-based communication. For experimentation and for understanding Cumulocity IoT’s REST interfaces, it is helpful to use one of the numerous available command line tools or browser extensions.

For example, many operating systems come with pre-installed tools such as the cURL command. If you want to start browsing the Cumulocity IoT APIs, enter on a command line:

$ curl -u <username>:<password> https://<yourTenant>.cumulocity.com/platform

Replace <username> and <password> with the username and password that you used to register to Cumulocity IoT. Similarly, replace <yourTenant> with your tenant URL.

The command will return links to all basic interfaces of Cumulocity IoT:

...
"inventory": {
    "managedObjects": {
        "references": [],
        "self": "https://<yourURL>/inventory/managedObjects"
    },
    "managedObjectsForFragmentType": "https://<yourURL>/inventory/managedObjects?fragmentType={fragmentType}",
    "managedObjectsForListOfIds": "https://<yourURL>/inventory/managedObjects?ids={ids}",
    "managedObjectsForType": "https://<yourURL>/inventory/managedObjects?type={type}",
    "self": "https://<yourURL>/inventory"
},
...

To format the output to a more readable way, pass it to the python -mjson.tool command:

$ curl -u <username>:<password> https://<yourTenant>.cumulocity.com/platform | python -mjson.tool

From this point, you can navigate further to the different returned objects. For instance, retrieve the items in the inventory by following the managedObjects endpoint:

$ curl -u <username>:<password> https://<yourTenant>.cumulocity.com/inventory/managedObjects

You will notice that just a subset of the items in the inventory is actually returned, a so-called “page”. More information on page handling can be found under Rest usage > Query result paging in the Cumulocity IoT OpenAPI Specification.

Using Postman

Graphical REST clients such as Postman are a convenient way to explore REST interfaces and the Cumulocity IoT database content.

Example REST client

Cumulocity IoT provides numerous online API examples. If you want to make use of them, download and install Postman. After starting Postman, you can choose to either create an account or click Take me straight to the app.

Download the API examples and import them as a collection into Postman.

Now, click the Collections tab on the top left of Postman. You should see a folder Cumulocity IoT API with the examples. Open that folder and the subfolder Alarms, then click Get collection of alarms. This shows an example on how to get alarms from Cumulocity IoT.

Note that the example contains placeholders, in this case a placeholder {{url}} in {{url}}/alarm/alarms. You must tell Postman how to fill these placeholders and by this, how to connect to your Cumulocity IoT account. To do so, create an environment and configure the placeholders.

Postman environment setup

For example, assume that your tenant ID is “t07007007”, your username is “winter” and your password is “jh0nS0nw”. A simple way to determine the correct value for the auth key is using the Base64 command as follows:

$ echo -n t07007007/winter:jh0nS0nw | base64

The resulting text is “dDA3MDA3MDA3L3dpbnRlcjpqaDBuUzBudw==” and you must use Basic dDA3MDA3MDA3L3dpbnRlcjpqaDBuUzBudw== as value for the auth key. You can achieve the same result also by using an online Base64 encode/decode tool.

Now it is time to start exploring the API!

Microservice development

This section will introduce you to the basic REST endpoints required for developing microservices. You will also learn the basic use cases in which the Cumulocity IoT REST APIs can be employed to develop microservice applications.

Creating applications

In order to start working with microservices, an instance of an application must be created on the platform beforehand. It can be done using the following endpoint:

POST /application/applications
Host: ...
Authorization: Basic ...
Content-Length: ...
Content-Type: application/vnd.com.nsn.cumulocity.application+json
{
  "key": "<APPLICATION_NAME>-key",
  "name": "<APPLICATION_NAME>",
  "type": "MICROSERVICE",
  "requiredRoles": [ "ROLE_INVENTORY_READ" ],
  "roles": [ "ROLE_CUSTOM_MICROSERVICE" ]
}

A success response consists of a 201 status and a location header similar to <HOST>/application/applications/<APPLICATION_ID>.

The properties key, name and type from the above request body are self explanatory, and about the roles:

The application ID for existing applications can be obtained employing a GET request with the name of the application:

GET /application/applicationsByName/<APPLICATION_NAME>
Host: ...
Authorization: Basic ...
Accept: application/vnd.com.nsn.cumulocity.application+json

The success response will look similar to:

{
    "applications": [
        {
            "activeVersionId": "329",
            "availability": "MARKET",
            "id": "174",
            "key": "<APPLICATION_NAME>-microservice-key",
            "manifest": {
                "imports": [],
                "noAppSwitcher": true
            },
            "name": "<APPLICATION_NAME>",
            "owner": {
                "self": "<HOST>/tenant/tenants/<TENANT>",
                "tenant": {
                    "id": "<TENANT>"
                }
            },
            "requiredRoles": [],
            "roles": [],
            "self": "<HOST>/application/applications/174",
            "type": "MICROSERVICE"
        }
    ],
    "next": "<HOST>/application/applications?pageSize=5&currentPage=2",
    "statistics": {
        "currentPage": 1,
        "pageSize": 5
    },
    "self": "<HOST>/application/applications?pageSize=5&currentPage=1"
}

The application can be updated afterwards by employing a PUT request:

PUT /application/applications/<APPLICATION_ID>
Host: ...
Authorization: Basic ...
Content-Length: ...
Content-Type: application/vnd.com.nsn.cumulocity.application+json
{
    "key": "<APPLICATION_NAME>-key",
    "name": "<APPLICATION_NAME>",
    "type": "MICROSERVICE",
    "requiredRoles": [ "ROLE_INVENTORY_READ" ],
    "roles": [ "ROLE_CUSTOM_MICSROSERVICE" ]
}

Deploying applications

A microservice application gets available for Cumulocity IoT platform users by uploading a binary ZIP file.

POST /application/applications/<APPLICATION_ID>/binaries
Host: ...
Authorization: Basic ...
Content-Type: multipart/form-data

The ZIP file must consist of:

Acquiring microservice credentials

The following section is a wrap up for user management as described under General aspects of microservices in Cumulocity IoT.

Microservice related endpoints require a microservice bootstrap user, which can be obtained by a service provider using:

GET /application/applications/<APPLICATION_ID>/bootstrapUser
Host: ...
Authorization: Basic ...

Response:

HTTP/1.1 200 Ok
Content-Type: application/vnd.com.nsn.cumulocity.user+json
{
    "tenant": "...",
    "name": "...",
    "password": "..."
}

These credentials allow access to the following endpoints:

GET /tenant/currentTenant
GET /user/currentUser
GET /application/currentApplication
GET /application/currentApplication/subscription
PUT /application/currentApplication

For example, to get the current application use:

GET /application/currentApplication
Authorization: Basic ...
Content-Type: application/json

Response:

{
    "activeVersionId": "329",
    "availability": "MARKET",
    "id": "...",
    "key": "...",
    "manifest": {
        "imports": [],
        "noAppSwitcher": true
    },
    "name": "hello-world",
    "owner": {
        "self": "...",
        "tenant": {
            "id": "..."
        }
    },
    "requiredRoles": [],
    "roles": [],
    "self": "...",
    "type": "MICROSERVICE"
}

Subscriptions

Subscription in this scope means tenant subscription to a microservice application. The subscription is an important step after deployment. When a microservice application is deployed it becomes available for subscription to other tenants. Subscribing to a microservice is the same as subscribing to any other application and it can be done in the Administration application. Also, a tenant can be subscribed employing a POST request:

POST /tenant/tenants/<TENANT>/applications
Host: ...
Authorization: Basic ...
Content-Length: ...
Content-Type: application/vnd.com.nsn.cumulocity.applicationreference+json
Accept: application/vnd.com.nsn.cumulocity.tenant+json
{
    "application": {
        "id": "<APPLICATION_ID>"
    }
}

A successful response will look similar to:

HTTP/1.1 201 Created
Content-Type: application/vnd.com.nsn.cumulocity.tenant+json
Content-Length: ...
{
    "application": {
        "id": "<APPLICATION_ID>",
        "key": "...",
        "name": "...",
        "owner": {
            "self": ".../tenant/tenants/<TENANT>",
            "tenant": {
                "id": "<TENANT>"
            }
        },
        "self": "...",
        "type": "MICROSERVICE"
    },
    "self": "..."
}

The subscriptions are available to microservice users through the authorized microservice bootstrap user.

GET /application/currentApplication/subscriptions
Host: ...
Authorization: Basic ...

Response:

HTTP/1.1 200 OK
Content-Type: application/vnd.com.nsn.cumulocity.applicationusercollection+json
{
    "users": [{
        "tenant": "...",
        "name": "...",
        "password": "..."
    }],
    "self": ".../applications/application/285/users"
}

The response consists of service user credentials dedicated for each tenant. A service user is a user account in the tenant that has the permissions (“roles”) that the microservice requested on registration time.

Settings

The microservice settings are available to microservice users through the authorized bootstrap or service user. When using the bootstrap user, all settings are always loaded for the microservice owner. The settings are stored in Cumulocity IoT as tenant options, where category is by default contextPath (or applicationName in case context path is not defined).

Request:

GET /application/currentApplication/settings
Host: ...
Authorization: Basic ...

Response:

HTTP/1.1 200 OK
Content-Type: application/vnd.com.nsn.cumulocity.option+json;charset=UTF-8;ver=0.9
{
   "email.protocol": "smtps",
   "password.enforce.strength": "true",
   "another.key.1": "$value15"
}

Basic use cases

Registering assets

Assets are the objects that your business and your application focuses on. For example, assets might be buildings and rooms if your business centers around building management or home automation. Or they might be routes and machines, if your business is about servicing machines.

Assets are stored in the inventory along with the devices, but they often have their own structure independent of devices. You create assets by POSTing them to the collection of managed objects in the inventory. For example, to create a new room in the inventory, use:

POST /inventory/managedObjects
Content-Type: application/vnd.com.nsn.cumulocity.managedobject+json
Accept: application/vnd.com.nsn.cumulocity.managedobject+json
Authorization: Basic ...
{
    "name": "Building 043",
    "type": "c8y_Building"
}

Response:

HTTP/1.1 201 Created
Content-Type: application/vnd.com.nsn.cumulocity.managedobject+json;charset=UTF-8;ver=0.9
...
{
    "owner": "admin",
    "id": "2549800",
    "self": "https://.../inventory/managedObjects/2549800",
    "type": "c8y_Building",
    "lastUpdated": "2018-09-05T16:38:31.250+02:00",
    "name": "Building 043",
    "assetParents": {
        "references": [],
        "self": "https://.../inventory/managedObjects/2549800/assetParents"
    },
    "childAssets": {
        "references": [],
        "self": "https://.../inventory/managedObjects/2549800/childAssets"
    },
    "childDevices": {
        "references": [],
        "self": "https://.../inventory/managedObjects/2549800/childDevices"
    },
    "deviceParents": {
        "references": [],
        "self": "https://.../inventory/managedObjects/2549800/deviceParents"
    }
}

If the device could be successfully created, a status code of 201 is returned. If the original request contains an “Accept” header just like in the example above, the complete created object is returned including the ID and URL to reference the object in future requests. The returned object also includes references to collections of child devices and child assets that can be used to add children to the device.

For example, assuming that we have also created a room, and that room’s “self” property is “https://…/inventory/managedObjects/2549700”, to link the room to the building, POST to the child assets collection of the building (see the “self” property of “childAssets” above):

POST /inventory/managedObjects/2549800/childAssets HTTP/1.1
Content-Type: application/vnd.com.nsn.cumulocity.managedobjectreference+json
{
    "managedObject" : {
        "self" : "https://.../inventory/managedObjects/2549700"
    }
}

Now querying the building again shows that the room has been registered as child of the building:

GET /inventory/managedObjects/2549800

Response:

HTTP/1.1 200 OK
Content-Type: application/vnd.com.nsn.cumulocity.managedobject+json; charset=UTF-8; ver=0.9
...
{
    "owner": "admin",
    "id": "2549800",
    "self": "https://.../inventory/managedObjects/2549800",
    ...
    "childAssets": {
        "references": [
            {
                "managedObject": {
                    "id": "2549700",
                    "name": "Room 042",
                    "self": "https://.../inventory/managedObjects/2549700"
                },
                "self": "https://.../inventory/managedObjects/2549800/childAssets/2549700"
            }
        ],
        "self": "https://.../inventory/managedObjects/2549800/childAssets"
    }
}

Linking devices to assets

Just like you link assets to other child assets, you can also link assets to devices that monitor and control the asset. For example, assume that you have a light sensor installed in the room, and that light sensor has the URL “https://…/inventory/managedObjects/2480500”. POST to childDevices of the room as follows:

POST /inventory/managedObjects/2549700/childDevices
Content-Type: application/vnd.com.nsn.cumulocity.managedobjectreference+json
{
    "managedObject" : {
        "self" : "https://.../inventory/managedObjects/2480500"
    }
}
Info
You can link multiple child assets or multiple child devices to the same parent in a single request. Refer to inventory child operations in the Inventory API in the Cumulocity IoT OpenAPI Specification for more details.

Synchronizing assets with external systems

Often, Cumulocity IoT will not be the only IT system dealing with a company’s asset. The technical procedure for synchronizing assets stored in external IT systems is exactly the same as the procedure used for registering devices:

Querying particular capabilities

To decouple applications from the specifics of particular types of devices, applications can use fragments to query the inventory (see the Fragments section of Cumulocity IoT’s domain model). For example, to find all managed objects having a location, use:

GET /inventory/managedObjects?fragmentType=c8y_Position&withTotalPages=true

Response:

HTTP/1.1 200 OK
Content-Type: application/vnd.com.nsn.cumulocity.managedobjectcollection+json; charset=UTF-8; ver=0.9
...
{
    "managedObjects": [{
        "id": "2480700",
        "lastUpdated": "2013-08-30T10:15:44.218+02:00",
        "name": "RaspPi BCM2708 0000000017b769d5 Gps eM9",
        "owner": "admin",
        "self": "https://.../inventory/managedObjects/2480700",
        "type": "c8y_TinkerForge_Gps",
        "c8y_Position": {
            "alt": 102.36,
            "lng": 6.769717,
            "lat": 51.267259
        },
        ...
    },
    ...
    ]
    "next": "https://.../inventory/managedObjects?withTotalPages=true&fragmentType=c8y_Position&pageSize=5&currentPage=2",
    "statistics": {
        "currentPage": 1,
        "pageSize": 5,
        "totalPages": 4
    },
    "self": "https://.../inventory/managedObjects?withTotalPages=true&fragmentType=c8y_Position&pageSize=5&currentPage=1"
}

Now you could, for example, use the c8y_Position property to locate/pin the object on a map. Standard fragments are defined in the Device management library and in the Sensor library.

Querying the /platform resource will show you further possibilities for querying your data (see also Device integration using REST in Device integration).

Note that queries do not necessarily return all query results at once, but only a page of the results. For more information on paging, refer to REST implementation > REST usage > Query result paging in the Cumulocity IoT OpenAPI Specification. The optional parameter withTotalPages will make the query contain full page statistics at the expense of slightly slower performance.

Querying readings from sensors

Similar to the inventory, you can also query for particular sensor readings. For example, you can query the light measurements of the past month (from the time of writing this text) as follows:

GET /measurement/measurements?dateFrom=2019-04-01&dateTo=2019-05-31&fragmentType=c8y_LightMeasurement

Response:

HTTP/1.1 200 OK
Content-Type: application/vnd.com.nsn.cumulocity.measurementcollection+json; charset=UTF-8; ver=0.9
...
{
    "measurements": [{
        "id": "2480900",
        "self": "https://.../measurement/measurements/2480900",
        "source": {
            "id": "2480500",
            "self": "https://.../inventory/managedObjects/2480500"
        },
        "time": "2013-08-29T21:19:52.321+02:00",
        "type": "c8y_LightMeasurement",
        "c8y_LightMeasurement": {
            "e": {
                "unit": "lux",
                "value": 169.2
            }
        }
    },
    ...
    ]
    ...
}

Sending operations to devices

To trigger an operation on a device, POST the operation to the Device Control API. The following example restarts the device with the ID “2480300” (which is the Raspberry Pi that is integrated in Device integration in Device integration.

POST /devicecontrol/operations
Content-Type: application/vnd.com.nsn.cumulocity.operation+json;
Accept: application/vnd.com.nsn.cumulocity.operation+json;
{
    "deviceId": "2480300",
    "c8y_Restart":{}
}

Response:

HTTP/1.1 201 Created
Content-Type: application/vnd.com.nsn.cumulocity.operation+json; charset=UTF-8; ver=0.9
...
{
    ...
    "deviceId": "2480300",
    "id": "2550200",
    "self": "https://.../devicecontrol/operations/2550200",
    "status": "PENDING",
    "c8y_Restart": {}
}

The POST command returns immediately when the operation has been queued for the device. The actual operation executes asynchronously. Since we added the optional “Accept” header in the example request, we will get the full queued operation in the response including its URL in the self property. Using a GET on that URL, you can check the current status of execution of the operation:

GET /devicecontrol/operations/2550200 HTTP/1.1

HTTP/1.1 200 OK
Content-Type: application/vnd.com.nsn.cumulocity.operation+json; charset=UTF-8; ver=0.9
{
    "status": "PENDING",
    ...
}

A status of PENDING means here that the device has not yet picked up the operation. EXECUTING means that the device is in the process of executing the operation. Finally, SUCCESSFUL or FAILED indicate that the operation is completed.

Listening for events

Besides querying the Cumulocity IoT data store, you can also process and receive events in real time. For example, assume that you would like to display real-time location updates on a map.

If you have a device that sends location updates, you should see them immediately in the user interface. To receive them in your own REST client, you can use the Notification API to subscribe to them. The API is based on the Bayeux protocol using HTTPS long-polling. The restrictions that apply are described in Real-time notifications in the Cumulocity IoT OpenAPI Specification. First, a handshake is required. The handshake tells Cumulocity IoT what protocols the client supports for notifications and allocates a client ID to the client.

POST /notification/realtime
Content-Type: application/json
...
[ {
    "id": "1",
    "supportedConnectionTypes": ["long-polling"],
    "channel": "/meta/handshake",
    "version": "1.0"
} ]

HTTP/1.1 200 OK
...
[ {
    "id": "1",
    "supportedConnectionTypes": ["long-polling"],
    "channel": "/meta/handshake",
    "version": "1.0",
    "clientId": "71fjkmy0495rxrkfcmp0mhcev1",
    "minimumVersion": "1.0",
    "successful": true
}]

After the handshake, the client must subscribe to the particular device channel or all devices channel (*). This is done using a POST request with the name of the channel.
For example, if you want to receive notifications about events from the device with internal ID “24800”, the subscription channel is “/events/24800”.

POST /notification/realtime
Content-Type: application/json
...
[ {
    "id": "2",
    "channel": "/meta/subscribe",
    "subscription": "/events/24800",
    "clientId": "71fjkmy0495rxrkfcmp0mhcev1"
}]

HTTP/1.1 200 OK
...
[ {
    "id":"2",
    "channel": "/meta/subscribe",
    "subscription": "/events/24800",
    "successful": true,
} ]

Finally, the client connects and waits for events to be sent to it.

POST /notification/realtime HTTP/1.1
Content-Type: application/json
...
[ {
    "id": "3",
    "connectionType": "long-polling",
    "channel": "/meta/connect",
    "clientId": "71fjkmy0495rxrkfcmp0mhcev1"
} ]

This request will hang until an operation is issued. Here is an example of a response with a single location update:

HTTP/1.1 200 OK
...
[
    {
        "id": "3",
        "data": {
            "creationTime": "...",
            "id": "2481400",
            "self": "https://.../event/events/2481400",
            "source": {
                "id": "24800",
                "name": "RaspPi BCM2708 0000000017b769d5 Gps eM9",
                "self": "https://.../inventory/managedObjects/24800"
            },
            "text": "Location updated",
            "time": "...",
            "type": "c8y_LocationUpdate",
            "c8y_Position": {
                "alt": 58.34,
                "lng": 6.769717,
                "lat": 51.267259
            },
            "channel": "/events/24800"
        },
        "successful": true,
        "channel": "/meta/connect"
    }
]
Info
A channel for all devices (*) is deprecated and should be avoided. Subscription on this channel may cause performance issues on both the client and the server side, and this option may be removed in future versions of Cumulocity IoT.