Code
Introduction
The ClearBlade IoT Platform utilizes a microservices model powered by a Code Engine
. The code engine allows for JavaScript (ES5) and has several built-in integrations to interact with your IoT assets. Following microservice practices, a new execution context is sandboxed and created upon invocation. Once the process is complete, it is destroyed.
There are four code asset types:
Microservice: A short-lived service expected to be completed within a fixed time (or is killed otherwise); default execution timeout is 60 seconds.
Stream service: A service configured to handle requests continuously with an infinite execution timeout.
Configuration: A library that contains a key-value object to be used as constants.
Library: A custom JavaScript library that can be imported into one or more code services.
Here is a code service tutorial.
Purpose
Microservices, a software development technique, allows for a high degree of modularity, scale, and parallelization – all essential for effectively building and running full-scale IoT applications.
Libraries
Libraries are reusable code sets that one or more code services can import.
Native libraries
Native libraries are available in every system and have an underlying Golang implementation. Each library is optimized for computational performance.
These libraries can be imported using requires.
Library | Description | Docs |
---|---|---|
clearblade | Interacts with collections, messaging, users, edges, and devices | |
log | Appends messages to a log | |
http | Makes outbound HTTPS requests | |
geo | Geospatial computation library | |
crypto | Creates cryptographical hashes | |
file_writer | Write files to host the filesystem | |
jsutil | JS utility library | |
mailer | Send an email directly from the host machine | |
net_cb | Net library | |
oauth2_lib | OAuth utility library |
Custom libraries
A developer can create a custom library with custom logic. Custom libraries can also be created by importing NPM packages. Here is an NPM import tutorial.
Services
A service is a short-lived microservice expected to be completed in a finite time capped by the execution timeout field in its settings (it is killed after the timeout). The default is 60 seconds.
Lifecycle
Invocation
A service can be invoked by:
1. A REST request to the API endpoint
2. Trigger event
3. Timer event
Our SDKs can be used as a REST client to accomplish the first REST option.
Context
Each code service has a name corresponding to an autogenerated function name.
For example, a code service named analyze
will have an autogenerated function like:
function analyze(req, resp) {}
This function will have two parameters, similar to Node’s Express library.
req
req
is an object containing these contextual values:
Key | Description | Type | Example |
---|---|---|---|
userEmail | The user’s email who invoked the service | string | user@clearblade.com |
params | JSON with parameters. The structure is based on the invocation type | object | {“key”:“value”} |
systemKey | System key for the system in which the code service is running | string | e095a19d0b94e48dee9bff87e5fd01 |
systemSecret | System secret for the system in which the code service is running | string | E095A19D0B9ACD9EFA86AEEDFCC001 |
userToken | Invoking the user’s OAuth token | string | U1hNa7o4bEXpiE4aGhb-79MQv4… |
isLogging | Whether logging is enabled | boolean | true |
userid | Internal UID associated with the invoking user | string | fc8cfcea0a96ebebc7f5d4edd414 |
resp
resp
is an object used to return values and exit the Code Service
. These methods are available in the resp
object:
resp.success
resp.error
resp.set
resp.status
resp.send
resp.success
resp.success = function (object | string){}
function analyze(req, resp) {
var message = "Everything went well!";
resp.success(output); // Service exits successfully with "Everything went well!"
}
resp.error
resp.error = function (object | string ){}
function analyze(req, resp) {
var message = "It broke!";
resp.error(error); // Service exits with failure with "It broke!"
}
resp.set This method has multiple signatures:
resp.set = function(string, string){}
resp.set(keyString, valueString)
: Adds or updates a header key to the HTTP response from a service. Example: resp.set("Content-Type", "text/html")
resp.set = function(object){}
resp.set({})
: Sets the response headers to those in the map. Replaces the header object to remove any headers added withresp.set(k,v)
. Example:
resp.set({
"Content-Type": "application/json",
"ClearBlade-UserToken: req.userToken"
})
resp.status
resp.status = function(int){}
resp.status(int)
: Changes the HTTP response code from a service. Example: resp.status(400)
resp.send
resp.send = function(object|string){} resp.send(value)
: Exits the service and returns the value as the response body. value
will be stringified if not already a string. value
will be sent as-is and not wrapped in our typical JSON response object. Example: resp.send({valueA: "ABC-123-DEF", valueB: 123})
Exit
The service will terminate its execution with resp.success
, resp.error
, or resp.send
. By default, if no exit method is called and the execution reaches the end, resp.success
will be called to exit.
Logs
Logs record and store the service response history. Each service can store up to 25 of the latest logs with a max size of 100KB each.
Requires
A code service can import a library using the Requires
feature. You can select one or more libraries to import within the code service in the Service settings.
The same library can be used for multiple code services.
Debugging
There is no native support for debugging line-by-line. It is recommended to use the log
method extensively, like so:
function ServiceA(req, resp) {
log("Something happened");
resp.success("All done");
}
Events
Events are actions or occurrences that happen in the ClearBlade system, and it responds to them through the associated code service’s execution. ClearBlade supports timer and trigger events:
Timers
Timers provide a mechanism where a ClearBlade code service can be scheduled to execute at certain time intervals. Timers are similar to Unix cron jobs, with a similar scheduling mechanism.
Some example timer configurations:
Run every five minutes starting now forever
Run 26 times every two weeks starting Friday, May 5th, 2023
Run once at midnight
Triggers
Triggers are a mechanism that ties a Trigger Source
action to invocate a code service. The trigger source and payload information can be accessed in the code service through the req.params
object. Add log(req)
to the Code Editor
to log the payload information when creating a trigger.
"params": {
"topic": "ClearBladeTopic",
"body": "214.312",
"userId": "8e89e2af0fc9cbeadfd6afb501",
"trigger": "Messaging::Publish"
}
Event source
The platform publishes every event, regardless of whether the event is created programmatically in a service or externally in the console.
$trigger
and $timer
are custom ClearBlade topics. Using a stream service instead of a micro-service is advisable when working with $timer
and $trigger
topics that often fire to prevent overloading the platform.
For more information on publishing event topics, click here.
Asset | Category | Action | Topic |
---|---|---|---|
Messaging | Publish | Publish |
|
Messaging | Subscriptions | Upon Subscribe |
|
Messaging | Subscriptions | Upon Unsubscribe |
|
Messaging | Connection | User Connected |
|
Messaging | Connection | User Disconnected |
|
Messaging | Connection | Device Connected |
|
Messaging | Connection | Device Disconnected |
|
Data | Table | Created |
|
Data | Table | Updated |
|
Data | Table | Deleted |
|
Data | Item | Created |
|
Data | Item | Updated |
|
Data | Item | Deleted |
|
Data | Item | Upserted |
|
User | n/a | Created |
|
User | n/a | Updated |
|
User | n/a | Deleted |
|
Device | n/a | Created |
|
Device | n/a | Updated |
|
Device | n/a | Deleted |
|
Edge/Platform | Platform | Platform Started |
|
Edge/Platform | Platform | Platform Connected on Edge |
|
Edge/Platform | Platform | Platform Disconnected on Edge |
|
Edge/Platform | Edge | Edge Started |
|
Edge/Platform | Edge | Edge Connected on Platform |
|
Edge/Platform | Edge | Edge Disconnected on Platform |
|
Timer | n/a | Create Timer |
|
Incoming objects examples
Ensure code service-relevant permissions are set before using triggers and timers.
The following is a list of categories grouped by action types, showing structures for incoming objects:
Messaging (Publish/Subscribe/Unsubscribe)
:
When a publish/subscribe/unsubscribe is made to ClearBlade’s MQTT broker:
// Template
{
"params": {
"topic": "<message_topic>",
"body": "<message_body>",
"userId": "<user_id>",
"trigger": "Messaging::<action_type>"
}
}
// Example
{
"params": {
"topic": "ClearBladeTopic",
"body": "example message",
"userId": "8e89e2af0fc9cbeadfd6afb501",
"trigger": "Messaging::Publish"
}
}
Messaging (UserConnected/UserDisconnected)
:
When a user connects/disconnects to ClearBlade’s MQTT broker:
// Template
{
"params": {
"email": "<user_email>",
"trigger": "Messaging::<action_type>"
}
}
// Example
{
"params": {
"email": "example@clearblade.com",
"trigger": "Messaging::MQTTUserDisconnected"
}
}
Messaging (DeviceConnected/DeviceDisconnected)
:
When a device connects/disconnects to ClearBlade’s MQTT broker:
// Template
{
"params": {
"deviceName": "<device_name>",
"trigger": "Messaging::<action_type>"
}
}
// Example
{
"params": {
"deviceName": "exampleDevice",
"trigger": "Messaging::MQTTDeviceDisconnected"
}
}
Data-Table (CollectionCreated/CollectionUpdated/CollectionDeleted)
:
// Template
{
"params": {
"collectionId": "<collection_id>",
"collectionName": "<collection_name>",
"trigger": "Data::<action_type>"
}
}
// Example
{
"params": {
"collectionId": "ceafb4cf0bbaf5f4ddfbf1b48730",
"collectionName": "ExampleCollection",
"trigger": "Data::CollectionCreated"
}
}
Data (ItemCreated)
:
// Template
{
"params": {
"items": [
{
"item_id": "<item_id>"
}
],
"collectionId": "<collection_id>",
"collectionName": "<collection_name>",
"trigger": "Data::ItemCreated"
}
}
//Example
{
"params": {
"items": [
{
"item_id": "083196bf-8059-46c0-8280-38234aa73fc1"
}
],
"collectionId": "ceafb4cf0bbaf5f4ddfbf1b48730",
"collectionName": "ExampleCollection",
"trigger": "Data::ItemCreated"
}
}
Data (ItemUpdated/ItemDeleted)
:
// Template
{
"params": {
"collectionId": "<collection_id>",
"collectionName": "<collection_name>",
"trigger": "Data::<action_type>",
"items": [
// First row
// This includes all of the data from the row
{
"<column1_name>": <column1_data>,
"item_id": "<item_id1>",
"<column2_name>": <column2_data>
}
// A second row
{
"<column1_name>": <column1_data>,
"item_id": "<item_id1>",
"<column2_name>": <column2_data>
}
]
}
}
// Example
{
"params": {
"collectionId": "ceafb4cf0bbaf5f4ddfbf1b48730",
"collectionName": "ExampleCollection",
"trigger": "Data::ItemUpdated",
"items": [
{
"hi": 6,
"item_id": "14b12adf-4c32-4740-8461-546daa660393",
"low": 3
},
{
"hi": 7,
"item_id": "3700fa91-ef49-41e8-9fe7-64e9ee6aa3b2",
"low": 5
}
]
}
}
User (UserCreated)
:
// Template
{
"params": {
"user": {
"creation_date": <date_time>,
"email": "<user_email>",
"user_id": "<user_id>"
},
"trigger": "User::UserCreated"
}
}
//Example
{
"params": {
"user": {
"creation_date": 2019-06-20T19:43:10Z,
"email": "example@clearblade.com",
"user_id": "9c87dfd00beefbd8a0f3cc82f0c001"
},
"trigger": "User::UserCreated"
}
}
User (UserUpdated/UserDeleted)
:
// Template
{
"params": {
"query": {
"FILTERS": [
[
{
"EQ": {
"user_id": "<user_id>"
}
}
]
],
"PAGENUM": <page_number>,
"PAGESIZE": <page_size>,
"SELECTCOLUMNS": <columns_selected>,
"SORT": []
},
// Includes all of the data from the row
"user": {
"email": "<user_email>"
<column1_name>: <row_data>
<column2_name>: <row_data>
"user_id": "<user_id>"
},
"trigger": "User::<action_type>"
}
}
// Example
{
"params": {
"query": {
"FILTERS": [
[
{
"EQ": {
"user_id": "9c87dfd00beefbd8a0f3cc82f0c001"
}
}
]
],
"PAGENUM": 0,
"PAGESIZE": 0,
"SELECTCOLUMNS": null,
"SORT": []
},
"user": {
"email": "example@clearblade.com"
"name": "Example"
"age": 22
"user_id": "9c87dfd00beefbd8a0f3cc82f0c001"
},
"trigger": "User::UserUpdated"
}
}
Device (DeviceCreated/DeviceDeleted)
:
// Template
{
"params": {
"trigger": "Device::<action_type>",
"device": {
"allow_certificate_auth": "<boolean>",
"allow_key_auth": "<boolean>",
"certificate": "<certificate>",
"created_date": "<date_time>",
"description": "<device_description>",
"device_key": "<device_key> :: <device_name>",
"enabled": "<boolean>",
"last_active_date": "<date_time>",
"<columnX_name>": "<columnX_data>",
"<columnY_name>": "<columnY_data>",
"system_key": "<system_key>",
"type": "<device_type>"
},
"deviceName": "<device_name>"
}
}
//Example
{
"params": {
"trigger": "Device::DeviceCreated",
"device": {
"allow_certificate_auth": true,
"allow_key_auth": true,
"certificate": "",
"created_date": 2019-06-20T19:43:10Z,
"description": "",
"device_key": "ccafb4cf0bd0dcbcadaccaf9ebba01 :: ExampleDevice",
"enabled": true,
"last_active_date": 2019-06-20T19:43:10Z,
"name": "ExampleDevice",
"state": "active",
"system_key": "ccafb4cf0bd0dcbcadaccaf9ebba01",
"type": "Sensor"
},
"deviceName": "ExampleDevice"
}
}
Device (DeviceUpdated)
:
// Template
{
"params": {
"changes": {
"description": "<device_description>"
},
"deviceName": "<device_name>",
"trigger": "Device::DeviceUpdated"
}
}
// Example
{
"params": {
"changes": {
"description": "device description"
},
"deviceName": "example_device",
"trigger": "Device::DeviceUpdated"
}
}
Edge/Platform
:
// Template
{
"params": {
"edgeName": "edge_name",
"trigger": "StartConnectDisconnect::<action_type>"
}
}
// Example
{
"params": {
"edgeName": "example",
"trigger": "StartConnectDisconnect::<Edge Started>"
}
}
Webhooks
A webhook is a mechanism that allows you to execute a code service by targeting a public endpoint. Any HTTP method, such as GET, POST, PUT, or DELETE, can be used and will result in executing the service. The URL we provide can be used by third parties to push real-time data to ClearBlade’s server. Multiple webhooks can invoke a code service and are syncable. See the tutorial.