Introduction
Before proceeding, please take a moment to register an account with NoLag. This will make it easier to follow along.
To stay up-to-date with future updates and get help, we encourage you to join our Discord server.
What is different about NoLag?
NoLag provides a seamless plug-and-play solution that enables real-time communication between devices.
Our core feature is "Reverse Queries".
Reverse query is where a publisher transmits messages on a specific topic attached to a set of Identifiers. Subscribers can they listen to the topic and a list of identifier based on the ACL credentials.
Supported languages
On the right, you'll find a list of language flavors. You can use the package manager commands listed to install the NoLag SDK.
If you're interested in creating your own integration, be sure to check out the NoLag Transport Protocolsection.
npm i nolagjs
yarn add nolagjs
Quick Example
Check out NoLag in action, we created a few demo examples.
Subscriber
Rider subscribing to driver location updates
/**
* ----- Create NoLag Tunnel connection -----
* */
import {
WebSocketClient,
stringToArrayBuffer,
uint8ArrayToString,
} from "nolag";
import type { ITopic, ITunnel, IResponse } from "nolag";
const accessToken: string = "<your_device_access_token_goes_here>";
const nolagInstance: ITunnel = await WebSocketClient(accessToken);
/**
* ----- SUBSCRIBE to Topic and set some identifiers to listen to -----
*/
const rideShareRider: ITopic = nolagInstance.subscribe("rideShareDriver", {
OR: [
"booking_id_1234",
],
});
/**
* ----- RECEIVE data on Topic name -----
*/
rideShareRider.onReceive((received: IResponse) => {
const { data, identifiers, topicName, presences } = received;
const stringData: string = uint8ArrayToString(data);
const receivedData = JSON.parse(stringData);
console.log(receivedData);
//{
// driverCurrentLocation: {
// lat: "1234",
// lng: "34564",
// },
// }
console.log(identifiers);
// ["booking_id_1234"]
console.log(topicName);
// rideShareDriver
console.log(presences);
// ["driver_id_6a9d03f5-bc0f-4516-9b51-c223a6cac0d2"]
});
Publisher
Driver publishing location to Rider. Notice the Presence property. Presence is a mechanism to update the Rider of the Drivers presence without having to constantly ping the Rider.
/**
* ----- PUBLISH some data to a topic and grouping of identifiers -----
*/
const rideShareDriverPayload: string = JSON.stringify({
driverCurrentLocation: {
lat: "1234",
lng: "34564",
},
});
// payload as ArrayBuffer
const payloadArrayBuffer: ArrayBuffer = stringToArrayBuffer(rideShareDriverPayload);
// identifiers
const identifiers: string[] = ["booking_id_1234"];
nolagInstance.publish("rideShareDriver", payloadArrayBuffer, identifiers);
Getting Started
Before we can start coping and pasting example code we first have to set up the environment.
Follow the below step
- Create a Project
- Create a Tunnel
- What are NQL identifiers?
- Create a Topic
- Authentication
- Usage and Billing
Create a Project
To get started, we need to create a new project. With a NoLag project, you can manage the following:
- User access.
- API key access.
- Project Billing
- Creating new Tunnels.
Create a Tunnel
The Tunnel serves as the pathway for data transmission between devices.
Some key points to keep in mind:
- Topics assigned to one Tunnel are isolated from other Tunnels, even if they share the same name.
- Each Tunnel allows for one socket connection only.
- Device tokens are bound to a single Tunnel.
- Tunnels have their own user management system, which makes it easy to grant specific access to different Tunnels.
Sandbox Tunnels
Sandbox Tunnels function exactly the same as regular Tunnels, with the only difference being resource limitations. All sandbox Tunnels share the same resource limits.
What are NQL identifiers?
NQL(NoLag Query Language) identifiers can be thought of as sub-Topics within the NoLag Query Language. These identifiers act as query points within the NoLag message broker and consist of a list of values.
this.playerMovement.addIdentifiers({
OR: [
"clanId:9482f8ee-26d0-4a92-97d3-95e99c764e59",
"surroundingTile:800:802",
"biome-4",
]});
this.playerMovement.removeIdentifiers(["surroundingTile:800:802"]);
As a Subscriber
The Subscriber can listen to the Topic and the list of identifiers attached to it. A list of identifiers represents a OR operation.
Ex. IdentifierOne OR IdentifierTwo
As a Publisher
The Publisher can send messages to the Topic and optionally specify one or more identifiers..
NQL identifiers
NQL identifiers are dynamic, meaning they can be added or removed from a Topic implemented by a device.
Flow diagram
In the diagram you can see two wind turbines each publishing one message to the Topic "turbineOutput" and each with a different set of NQL identifiers.
NoLag will then distribute the messages to the Subscribers using the NQL identifiers.
Create a Topic
Topics are the events or triggers that a Subscriber will listen to and a Publisher will send data to. Topics are attached to a Tunnel, which is grouped under a Project.
Topics are static
Topics are static and created in the NoLag portal or via API calls. They can only be changed or removed from a Tunnel via the portal or API calls. Having static Topics and dynamic NQL identifiers makes it easier to build secure, scalable real-time applications.
While Topics are static, you can easily set or remove a Topic from a subscriber. Topics have several features, including:
- NoEcho This is switched on by default. A device could subscribe and publish on the same Topic name. NoEcho, as the name suggests, stops the publisher from sending data to its own subscription.
- Advance webhook - Trigger Every time messages are sent to a Topic, message data can be sent to an API endpoint.
- Advance webhook - Hydrate When a device connects to the NoLag message broker, the device could be hydrated with data from a specific endpoint.
- Status A Topic can be switched off.
Authentication
Device access Tokens are a key feature of NoLag and the cornerstone for securing device connections. All connections to a Tunnel require a Device Token, which can have several options:
- Access Permission
Determines the level of access the Device Token has, including the ability to publish and subscribe to Topics, publish only, or subscribe only. - Expire in
Specifies how long the Device Token will remain valid, in seconds. - Lock Topics
Prevents the device from subscribing or publishing to Topics that are not on the allowed list. - Allowed Topics
A list of Topics and Identifiers that are assigned to a Device Token. If the Device Token is not locked, the device can also subscribe or publish to other Topics not on the list. - Load Balancing: Round-Robin
With this option enabled, devices that share a device token ID will receive messages in a "round-robin" fashion.
Usage and Billing
Message Size
There are no publishing frequency limits but there are payload size limits.
Message transport data size can not exceed 50KB. Exceeding the allowed transport size will disconnect your device from the Tunnel.
Message transport size is made up of "topicName", "identifiers" and "payload".
Connection cost
Client will be billed for the number of seconds a device is connected to a Tunnel server.
Data transfer cost
Clients will be billed for the number of bytes egressing the Tunnel servers. This will also include data being sent between Tunnel locations.
Ex. If all your clients are in one region you will only be billing for data leaving the Tunnel server.
Ex. If you have clients all over the world and data is being sent between Tunnels servers, you will be billed for data leaving each Tunnel location and also data traveling between Tunnel locations.
Billing period
The billing period is based on a monthly cycle and starts on the first day of the month. At the end of each billing cycle, clients will receive an invoice for their usage.
Pricing model
NoLag follows a usage-based pricing model, meaning that clients are only charged for the resources they consume during the billing period. There are no upfront costs or long-term commitments.
Billing details
Clients can view their usage and billing details in the NoLag dashboard, which provides real-time visibility into their data transfer and connection costs. The dashboard also allows clients to set up alerts and notifications for cost thresholds and usage limits.
Client SDK
Connecting to a Tunnel
npm i nolagjs
yarn add nolagjs
pnpm add nolagjs
Install your flavour of NoLag SDK from your preferred package manager.
Client instance
Import function |
---|
WebSocketClient |
Argument | Required | Type | Description |
---|---|---|---|
deviceToken | true | string | Device token generated via NoLag portal or API. |
Return
Tunnel Instance
Tunnel Instance
// import package
import { WebSocketClient } from "nolag";
import type { ITunnel, ITopic } from "nolag";
const deviceToken: string = "<device_token_goes_here>";
// Connect to Tunnel
const nolagClient: ITunnel = await WebSocketClient(deviceToken);
// get device token ID
console.log(nolagClient.deviceTokenId);
Methods
Instances
Properties
Callbacks
Subscribe to a Topic
Subscribe to Topic
const topicOne: ITopic = nolagClient.subscribe("topicOne");
Subscribe to Topic with NQL identifiers attached
const topicTwo: ITopic = nolagClient.subscribe("topicTwo", {
OR: [
"identifier_1",
"identifier_2",
"identifier_3",
]});
You can subscribe to any valid Topic name. Topic names are created in the NoLag portal or via an API call.
Method call
Instance | Method name |
---|---|
TunnelInstance | subscribe |
Argument | Required | Type | Description |
---|---|---|---|
topicName | yes | string | Name of the topic you want to subscribe to. |
identifiers | no | INqlIdentifiers | List of NQL identifiers attached to Topic Name |
Return
Publish on a Topic
Publish message
import { stringToArrayBuffer } from "nolag";
// required
const topicName: string = "topicTwo";
// required
const payload: ArrayBuffer = stringToArrayBuffer("This is your first message");
// optional
const identifiers: IErrorsModel = {
OR: ["identifier_4"]
};
nolagClient.publish(topicName, payload, identifiers);
Instance | Method name |
---|---|
TunnelInstance | publish |
Argument | Required | Type | Description |
---|---|---|---|
topicName | yes | string | Name of the topic you want to send a message to. |
payload | yes | ArrayBuffer | Data to send via Topic name. |
identifiers | no | [...value{string}] | List of NQL identifiers attached to Topic Name |
Unsubscribe from Topic
Unsubscribe
nolagClient.removeTopic("topicOne");
Method call
Instance | Method name |
---|---|
TunnelInstance | removeTopic |
Argument | Required | Type | Description |
---|---|---|---|
topicName | yes | string | The name of the topic you want to unsubscribe from. |
Return
boolean
Get Topic instance
Get Topic
const topicOne: ITopic = nolagClient.getTopic("topicOne");
Method call
Instance | Method name |
---|---|
TunnelInstance | getTopic |
Argument | Required | Type | Description |
---|---|---|---|
topicName | yes | string | The name of the topic instance. |
Return
Disconnect
Disconnect
nolagClient.disconnect();
Method call
Instance | Method name |
---|---|
TunnelInstance | disconnect |
Return
Receive message callback
Receive message
import { uint8ArrayToString } from "nolag";
nolagClient.onReceive((received) => {
const { data, topicName, nqlIdentifiers, presences } = received;
const parseData = JSON.parse(uint8ArrayToString(data));
});
Instance | Method name |
---|---|
TopicInstance | onReceive |
Argument | Required | Type | Description |
---|---|---|---|
callbackFn | yes | Function | Callback will fire on message received |
Callback Function
Argument | Required | Type | Description |
---|---|---|---|
received | yes | ITransport |
Disconnect callback
On Disconnect
nolagClient.onDisconnect(() => {
// lost connection
});
Method call
Instance | Method name |
---|---|
TunnelInstance | onDisconnect |
Argument | Required | Type | Description |
---|---|---|---|
callbackFn | yes | Function | Callback will fire after connection loss |
Return
Re-connect callback
On Reconnect
nolagClient.onReconnect(() => {
// successful connection made
});
Method call
Instance | Method name |
---|---|
TunnelInstance | onReconnect |
Argument | Required | Type | Description |
---|---|---|---|
callbackFn | yes | Function | Callback will fire when device reconnects |
Return
On error callback
On Error
nolagClient.onError((errors: ConnectionErrors) => {
// received errors
console.log(errors);
});
Method call
Instance | Method name |
---|---|
TunnelInstance | onError |
Argument | Required | Type | Description |
---|---|---|---|
callbackFn | yes | Function | Callback will fire on any connection errors |
Callback Function
Argument | Required | Type | Description |
---|---|---|---|
errors | yes | ConnectionErrors | Errors sent from message broker |
Return
Properties
Device Token ID
Device Token ID
console.log(nolagClient.deviceTokenId);
Property | Description |
---|---|
deviceTokenId | Device Token is a unique identifier that is used to authenticate a device and grant it access to a specific Tunnel. It is attached to the token used to connect to the Message Broker, allowing the device to establish a secure and authorized connection. |
Topic Instance
Topic Instance
let topicTwo: ITopic = nolagClient.subscribe("topicTwo");
// or if you already subscribed to "topicTwo" then use the below method
topicTwo: ITopic = nolagClient.getTopic("topicTwo");
When you subscribe to a Topic you get access to the topic instance. You can also access the Topic instance via the Tunnel instance using the getTopic method.
Methods
Callbacks
ADD NQL identifiers
Add Identifiers to Topic
topicTwo.addIdentifiers({
OR: [
"identifier_1",
"identifier_2",
"identifier_3",
"identifier_4",
]});
Instance | Method name |
---|---|
Topic | addIdentifiers |
Argument | Required | Type | Description |
---|---|---|---|
identifiers | true | [...value{string}] | Extra list of strings that the device will be listening. |
Return
REMOVE NQL identifiers
Remove identifiers
topicTwo.removeIdentifiers(["identifier_1", "identifier_2"]);
Instance | Method name |
---|---|
Topic | removeIdentifiers |
Argument | Required | Type | Description |
---|---|---|---|
identifiers | true | [...value{string}] | Remove identifiers from your subscription |
Return
Presence
Add device presence
topicTwo.setPresence("userId");
What is Presence
Presence is data you attach to a device that is subscribed to a Topic. If you set Presence data on a Topic, and another device subscribes to the same Topic with the same Identifiers. Both Devices will be sent each others "Presence Data".
Ex. Users connecting to a chat room. As soon as a user connects you will receive their presence data, and they will receive yours. You can attach any data which could be a UUID, the users name or a URL to an avatar.
Instance | Method name |
---|---|
Topic | setPresence |
Argument | Required | Type | Description |
---|---|---|---|
data | true | string | Any data that you would like to attach to a device |
Return
Topic publish
Publish message
import { stringToArrayBuffer } from "nolag";
// required
const payload: ArrayBuffer = stringToArrayBuffer("This is your second message");
// optional
const identifiers: INqlIdentifiers = {
OR: ["identifier_4"]
};
topicTwo.publish(payload, identifiers);
Instance | Method name |
---|---|
TopicInstance | publish |
Argument | Required | Type | Description |
---|---|---|---|
payload | true | string | Message you want to send to the Topic. |
identifiers | optional | [...value{string}] | Send messages only to these identifiers |
Return
Receive message callback
Receive message
import { uint8ArrayToString } from "nolag";
topicTwo.onReceive((received) => {
const { data, topicName, nqlIdentifiers } = received;
const parseData = JSON.parse(uint8ArrayToString(data));
});
Instance | Method name |
---|---|
TopicInstance | onReceive |
Argument | Required | Type | Description |
---|---|---|---|
callbackFn | yes | Function | Callback will fire on message received |
Callback Function
Argument | Required | Type | Description |
---|---|---|---|
received | yes | ITransport |
Unsubscribe
Unsubscribe
topicTwo.unsubscribe();
Method call
Instance | Method name |
---|---|
Topic | unsubscribe |
Return
boolean
API
Create API instance
API instance is used for all API calls.
import { Api, IApiTunnel } from "nolag";
const apiKey = "[api_key_goes_here]";
const nolagApi: IApiTunnel = await Api(accessToken);
Before you can make use of the API you need to generate a API token in the NoLag portal.
Methods
- Message Broker
- Tunnel methods
- Topic methods
- Device methods
Project Tunnels
Returns a list of Tunnels attached to a Project
curl "https://api.nolag.app/v1/tunnels" \
-X POST \
-H "X-API-Key: [api_key_goes_here]"
-H "Content-Type: application/json"
await nolagApi.tunnels();
HTTP Request
POST https://api.nolag.app/v1/tunnels
Method
Instance | Method name |
---|---|
ApiTunnel | tunnels |
Argument | Required | Type | Description |
---|---|---|---|
tunnelQuery | no | ITunnelQuery | Query params for Tunnels |
Response
Argument | Type |
---|---|
records | [...ITunnelModel] |
pagination | IPagination |
Tunnel Topics
Topics attached to a tunnel
Topic Create
Returns a list of Topics attached to a Tunnel
curl "https://api.nolag.app/v1/tunnels/:tunnelId/topics" \
-X POST \
-H "X-API-Key: [api_key_goes_here]"
-H "Content-Type: application/json"
-d "[payload_goes_here]"
const payload: ITopicModel = {
name: "TestTopic",
status: "active",
type: "active",
triggerApi: "active",
hydrateApi: "active",
noEcho: false,
};
await nolagApi.tunnel("[tunnel_id_goes_here]").topic.createTopic(payload);
HTTP Request
POST https://api.nolag.app/v1/tunnels/:tunnelId/topics
Method
Instance | Namespace | Method name |
---|---|---|
ApiTunnel | tunnel.topic | createTopic |
Argument | Required | Type | Description |
---|---|---|---|
topicModel | yes | ITopicModel |
response
Topic Get Record
Get all records for
curl "https://api.nolag.app/v1/tunnels/:tunnelId/topics/:topicId" \
-X GET \
-H "X-API-Key: [api_key_goes_here]"
-H "Content-Type: application/json"
await nolagApi
.tunnels("[tunnel_id_goes_here]")
.topic.getTopic("[topic_id_goes_here]");
HTTP Request
GET https://api.nolag.app/v1/tunnels/:tunnelId/topics/:topicId
Method
Instance | Namespace | Method name |
---|---|---|
ApiTunnel | tunnel.topic | getTopic |
Argument | Required | Type | Description |
---|---|---|---|
TopicId | yes | string |
response
Topic Update
Update Topic attached to a Tunnel
curl "https://api.nolag.app/v1/tunnels/:tunnelId/topics/:topicId" \
-X PATCH \
-H "X-API-Key: [api_key_goes_here]"
-H "Content-Type: application/json"
-d "[payload_goes_here]"
const payload: ITopicModel = {
name: "TestTopic",
status: "active",
type: "active",
triggerApi: "active",
hydrateApi: "active",
noEcho: false,
};
await nolagApi
.tunnels("[tunnel_id_goes_here]")
.topic.updateTopic("[topic_id_goes_here]", payload);
HTTP Request
PATCH https://api.nolag.app/v1/tunnels/:tunnelId/topics/:topicId
Method
Instance | Namespace | Method name |
---|---|---|
ApiTunnel | tunnel.topic | updateTopic |
Argument | Required | Type | Description |
---|---|---|---|
topicModel | yes | ITopicModel |
response
Topic Delete
Delete a Topic
curl "https://api.nolag.app/v1/tunnels/:tunnelId/topics/:topicId" \
-X DELETE \
-H "X-API-Key: [api_key_goes_here]"
-H "Content-Type: application/json"
await nolagApi
.tunnels("[tunnel_id_goes_here]")
.topic.deleteTopic("[topic_id_goes_here]");
HTTP Request
DELETE https://api.nolag.app/v1/tunnels/:tunnelId/topics/:topicId
Method
Instance | Namespace | Method name |
---|---|---|
ApiTunnel | tunnel.topic | deleteTopic |
Argument | Required | Type | Description |
---|---|---|---|
topicModel | yes | ITopicModel |
response
Topic List
Get a list of Topics
curl "https://api.nolag.app/v1/tunnels/:tunnelId/topics?[query_params_go_here]" \
-X GET \
-H "X-API-Key: [api_key_goes_here]"
-H "Content-Type: application/json"
await nolagApi
.tunnels("[tunnel_id_goes_here]")
.topic.listTopics("[topic_id_goes_here]");
HTTP Request
GET https://api.nolag.app/v1/tunnels/:tunnelId/topics?[query_params_go_here]
Method
Instance | Namespace | Method name |
---|---|---|
ApiTunnel | tunnel.topic | listTopics |
Argument | Required | Type | Description |
---|---|---|---|
topicQuery | no | ITopicQuery |
Response
Argument | Type |
---|---|
records | [...ITopicModel] |
pagination | IPagination |
Tunnel Devices
ACL management for Tunnel devices and Access Tokens
Device Create
Create a new device attached to a Tunnel
curl "https://api.nolag.app/v1/tunnels/:tunnelId/devices" \ -X POST \ -H "X-API-Key: [api_key_goes_here]" -H "Content-Type: application/json" -d "[payload_goes_here]"
const payload: IDeviceTokenModel = {
name: "TestDevice",
accessPermission: EAccessPermission.PubSub,
staticTopics: null,
lockTopics: false,
expireIn: 1000,
expireIn: 1000,
loadBalance: ELoadBalanceType.RoundRobin,
};
await nolagApi.tunnels("[tunnel_id_goes_here]").devices.createDevice(payload);
HTTP Request
POST https://api.nolag.app/v1/tunnels/:tunnelId/devices
Method
Instance | Namespace | Method name |
---|---|---|
ApiTunnel | tunnels.devices | createDevice |
Argument | Required | Type | Description |
---|---|---|---|
deviceTokenModel | yes | IDeviceTokenModel |
response
Device Get Record
Get a single device using Device Token Id
curl "https://api.nolag.app/v1/tunnels/:tunnelId/devices/:deviceTokenId" \
-X GET \
-H "X-API-Key: [api_key_goes_here]"
-H "Content-Type: application/json"
await nolagApi
.tunnels("[tunnel_id_goes_here]")
.devices.getDevice("[device_id_goes_here]");
HTTP Request
GET https://api.nolag.app/v1/tunnels/:tunnelId/devices/:deviceTokenId
Method
Instance | Namespace | Method name |
---|---|---|
ApiTunnel | tunnels.devices | getDevice |
Argument | Required | Type | Description |
---|---|---|---|
deviceTokenId | yes | string |
response
Device Update
Update device attached to the Tunnel
curl "https://api.nolag.app/v1/tunnels/:tunnelId/devices/:deviceTokenId" \
-X PATCH \
-H "X-API-Key: [api_key_goes_here]"
-H "Content-Type: application/json"
-d "[payload_goes_here]"
const payload: IDeviceTokenModel = {
name: "TestDevice",
accessPermission: EAccessPermission.PubSub,
staticTopics: null,
lockTopics: false,
expireIn: 1000,
loadBalance: ELoadBalanceType.RoundRobin,
};
await nolagApi
.tunnels("[tunnel_id_goes_here]")
.devices.updateDevice("[device_id_goes_here]", payload);
HTTP Request
PATCH https://api.nolag.app/v1/tunnels/:tunnelId/devices/:deviceTokenId
Method
Instance | Namespace | Method name |
---|---|---|
ApiTunnel | tunnels.devices | updateDevice |
Argument | Required | Type | Description |
---|---|---|---|
deviceTokenModel | yes | IDeviceTokenModel |
response
Device Delete
Delete a device using device ID
curl "https://api.nolag.app/v1/tunnels/:tunnelId/devices/:deviceTokenId" \
-X DELETE \
-H "X-API-Key: [api_key_goes_here]"
-H "Content-Type: application/json"
await nolagApi
.tunnels("[tunnel_id_goes_here]")
.devices.deleteDevice("[device_id_goes_here]");
HTTP Request
DELETE https://api.nolag.app/v1/tunnels/:tunnelId/devices/:deviceTokenId
Method
Instance | Namespace | Method name |
---|---|---|
ApiTunnel | tunnel.devices | deleteDevice |
Argument | Required | Type | Description |
---|---|---|---|
deviceId | yes | string |
response
Device List
Get a list of devices based of query params.
curl "https://api.nolag.app/v1/tunnels/:tunnelId/devices?[query_params_go_here]" \
-X GET \
-H "X-API-Key: [api_key_goes_here]"
-H "Content-Type: application/json"
await nolagApi
.tunnels("[tunnel_id_goes_here]")
.devices.listDevices({
name: "deviceOne",
});
HTTP Request
GET https://api.nolag.app/v1/tunnels/:tunnelId/devices?[query_params_go_here]
Method
Instance | Namespace | Method name |
---|---|---|
ApiTunnel | tunnels.devices | listDevices |
Argument | Required | Type | Description |
---|---|---|---|
deviceListQuery | yes | IDeviceListQuery |
Response
Argument | Type |
---|---|
records | [...IDeviceTokenModel] |
pagination | IPagination |
Publish messages
Publish messages to the NoLag via an HTTP request
curl "https://tunnel.nolag.app/tunnels/:tunnelId/publish" \
-X POST \
-H "X-API-Key: [api_key_goes_here]"
-H "Content-Type: text/plain"
-d "[payload_goes_here]"
import { stringToArrayBuffer, IHttpPublish } from "nolag";
const payload: IHttpPublish = {
data: stringToArrayBuffer(
JSON.stringify({
bulbStatus: true,
})
),
tunnelName: "topicTwo",
identifiers: ["identifier_1", "identifier_4"],
};
await nolag.publish(payload);
HTTP Request
POST https://tunnel.nolag.app/tunnels/:tunnelId/publish
Method
Instance | Namespace | Method name |
---|---|---|
ApiTunnel | tunnels | publish |
Argument | Required | Type | Description |
---|---|---|---|
httpPublish | true | IHttpPublish |
Response
boolean
Webhooks
How it works
- NoLag supports two types of webhooks.
- Both of these webhooks are attached to Topic.
- Both webhooks support Query and Header parameters.
- Data received from webhooks is in JSON format.
Webhook Types
Triggers Webhook
Trigger webhook is triggered when a message is published to a Topic.
{
topicName: 'factory',
identifiers: [ '373d521118f04b85810f4bba88d14a46' ],
deviceId: '2a39a946-4556-4f4d-bb48-ee11cab54d18',
data: "{message: 'hello'}"
}
As the name implies, this webhook is triggered when a message is published to a Topic.
You attach a Trigger webhook to a Topic in the NoLag portal.
Received JSON data from NoLag
Argument | Type | Description |
---|---|---|
topicName | string | Topic name that actioned this trigger |
identifiers | [...string] | NQL identifiers attached to the Topic name |
deviceId | string | Which device actioned the trigger |
data | string | Data triggered by Topic |
Hydration Webhook
Hydration webhook is triggered when a device connects to NoLag.
{
topicName: 'factory',
identifiers: [ '373d521118f04b85810f4bba88d14a46' ],
deviceId: '2a39a946-4556-4f4d-bb48-ee11cab54d18'
}
Hydrate device with data from an API end-point.
You attach a Hydrate webhook to a Topic in the NoLag portal.
Received JSON data from NoLag
Argument | Type | Description |
---|---|---|
topicName | string | Topic name that actioned this trigger |
identifiers | [...string] | NQL identifiers attached to the Topic name |
deviceId | string | Which device actioned the trigger |
Hydration response
This can be in any data format. NoLag will pass this data to the device without modification.
Transport Protocol
If your project doesn't have SDK support yet, this guide will help you get set up.
Servers
We use GEO routing. All you need to do is reference this URL and our infrastructure will route the request to the closest NoLag node.
Websocket Tunnel URL
wss://tunnel.nolag.app/ws
Authentication sequence
The following steps explain the connection and authentication of a connecting device
- Device connects to NoLag
- NoLag sends back a SOH to the device
- The device sends SI with
deviceAccessToken
to NoLag - (Only on re-connect) The device sends SI with
deviceAccessToken
and a SYN command to NoLag - NoLag sends back ACK and the deviceTokenId
Example sequence seen from the device:
SOH
SI[deviceAccessToken]
SI[deviceAccessToken]SYN <-- only on re-connect
ACK[deviceTokenId]
[transport_payload_here]
Transport Payload
Transport payload is how you communicate with NoLag. The payload consists of commands, and optionally device data to be sent.
[COMMAND][ACTION][GS][device_data]
Commands and device data are separated by a GS symbol.
NOTES:
- Command Actions could contain a list of data separated by US (unit separator) symbol.
- [VT] or Identifier commands will have an action of identifiers
- Command always prefixes an Action
- [GS] Symbol always splits the Commands/Actions and Device Data
- Device data is always at the end of the transport payload (after the GS symbol)
Transport Example
Subscribe to Topic "MyTopicName", and set two identifiers, "identifierOne" and "identifierTwo".
[SUB]MyTopicName[VT]IdentifierOne[US]IdentifierTwo[US][FF]
Explanation:
- The
[SUB]
command tells NoLag that you would like to SUBSCRIBE toMyTopicName
- The
[VT]
command tells NoLag that you would like to add identifiers - The
[US]
command tells NoLag that there is a listIdentifierOne
andIdentifierTwo
, because this list is mentioned after the[VT]
command, this list command becomes the action - The
[FF]
is an ADD command. It means we want to add these to the connection state
Hex transport:
1A 4D 79 54 6F 70 69 63 4E 61 6D 65 0B 49 64 65 6E 74 69 66 69 65 72 4F 6E 65 1F 49 64 65 6E 74 69 66 69 65 72 54 77 6F 1F 0C
Commands
Connect to NoLag
NoLag will send a SOH command as soon as the device successfully connects
DEC | HEX | BIN | Symbol | Has Action |
---|---|---|---|---|
1 | 01 | 00000001 | SOH | NO |
ASCII Example:
SOH
Authenticate on NoLag
Send device access token to NoLag to authenticate the device.
DEC | HEX | BIN | Symbol | Has Action |
---|---|---|---|---|
15 | 0F | 00001111 | SI | YES |
ASCII Example:
SI<deviceAccessToken>
Acknowledge
Acknowledges anything successfully. This could be a connection to NoLag or acknowledging a message was received.
DEC | HEX | BIN | Symbol | Has Action |
---|---|---|---|---|
6 | 06 | 00000110 | ACK | YES |
ASCII Example:
ACK<any_acknowledgment_ID>
Reconnect to NoLag
We add the SYN symbol to the Authenticate on NoLag transport to re-stabling the device connection state. We use this when the device looses internet connection. This command will re-establish all Topic and Identifier subscriptions.
DEC | HEX | BIN | Symbol | Has Action |
---|---|---|---|---|
22 | 16 | 00010110 | SYN | YES |
ASCII Example:
SI<deviceAccessToken>SYN
Subscribe to Topic only
Subscribe to a valid Topic. Valid Topics are created in the NoLag portal. Remember to add the FF
command.
DEC | HEX | BIN | Symbol | Has Action |
---|---|---|---|---|
26 | 1A | 00011010 | SUB | YES |
ASCII Example:
SUB<ValidTopic>FF
Subscribe to Topic and Identifiers
Subscribe to a valid Topic and identifiers. VT
command will always be followed by a list of Identifiers.
List of Identifiers are separated by US
. Remember to add the FF
command.
DEC | HEX | BIN | Symbol | Has Action |
---|---|---|---|---|
11 | 0B | 00001011 | VT | YES |
ASCII Example:
SUB<ValidTopic>VT<identifierOne>US<identifierTwo>USFF
Signify a list of data
We create a list of data as part of the transport with the US
command. Here the pattern is slightly different. We suffix the command from the data.
DEC | HEX | BIN | Symbol | Has Action |
---|---|---|---|---|
31 | 1F | 00011111 | US | YES |
ASCII Example:
<identifierOne>US<identifierTwo>US
Handle device presence
Presence is a why for devices to discover one another that are listening to Topic and Identifiers, without needing to constantly ping devices. Presence signifies when a device connects to NoLag, and when they disconnect. We piggyback of the standard subscription transports to attach a devices presence.
DEC | HEX | BIN | Symbol | Has Action |
---|---|---|---|---|
14 | 0E | 00001110 | SO | YES |
ASCII Example:
Send presence: SO<presenceDataOne>
Receive presences: SO<presenceDataOne>US<presenceDataOne>US
Full send presence example:
SUB<ValidTopic>VT<identifierOne>US<identifierTwo>USSO<presenceDataOne>FF
Full receive presence example:
SUB<ValidTopic>VT<identifierOne>US<identifierTwo>USSO<presenceDataOne>US<presenceDataOne>USFF
Unsubscribe from Topic
Device stop listening to Topic name.
DEC | HEX | BIN | Symbol | Has Action |
---|---|---|---|---|
16 | 10 | 00010000 | DLE | NO |
ASCII Example:
SUB<ValidTopic>DLE
Unsubscribe from Topic and Identifiers
Device stop listening to Topic Identifiers.
DEC | HEX | BIN | Symbol | Has Action |
---|---|---|---|---|
16 | 10 | 00010000 | DLE | NO |
ASCII Example:
SUB<ValidTopic>VT<identifierOne>US<identifierTwo>USDLE
Publish to a Topic
The GS command signifies data being sent or received by the device. We have to supply which Topic the data is attached to.
DEC | HEX | BIN | Symbol | Has Action |
---|---|---|---|---|
29 | 1D | 00011101 | GS | YES |
ASCII Example:
GS<deviceData>
Full example send and receive:
SUB<ValidTopic>GS<deviceData>
Publish to a Topic and Identifiers
The GS command signifies data being sent or received by the device. We have to supply which Topic and Identifiers the data is attached to.
DEC | HEX | BIN | Symbol | Has Action |
---|---|---|---|---|
29 | 1D | 00011101 | GS | YES |
ASCII Example:
GS<deviceData>
Full example send and receive:
SUB<ValidTopic>VT<identifierOne>US<identifierTwo>USGS<deviceData>
Types
Enums
EAccessPermission
Used to specify which type of Pub/Sub access the associated Device Token has.
Device permissions
Key | Value | Description |
---|---|---|
Subscribe | "subscribe" | Can only Subscribe |
Publish | "publish" | Can only Publish |
PubSub | "pubSub" | Can Publish and Subscribe |
EStatus
Set the status of a Topic. Active, the Topic can be used. Inactive, Topic can not be used.
Key | Value | Description |
---|---|---|
Active | "active" | |
Inactive | "inactive" |
ELoadBalanceType
How message will be delivered to devices sharing the same device token.
Key | Value | Description |
---|---|---|
RoundRobbin | "roundRobin" |
Interfaces
IPaginated
Paginated result received from the API end-point.
Property | Type | Description |
---|---|---|
records | [...DTO] | List of records |
pagination | IPagination |
IPagination
Pagination details indicating the current status of your pagination query.
Key | Type | Description |
---|---|---|
page | integer | Current page |
size | integer | Records per page |
hasPrevious | boolean | From the current page, are there any previous records |
hasNext | boolean | From the current page, are there any next records |
total | integer | Total number of records |
IDeviceListQuery
Available query parameters to query a device list.
Key | Type | Description |
---|---|---|
deviceAccessToken | string | This token is your access token key |
expireFromDate | integer | Find expire dates after this date |
expireToDate | integer | Find expire dates before this date |
name | string | Name of the Device |
search | string | search for names |
size | integer | Number of records on the page |
page | integer | Page number |
INqlIdentifiers
Available query parameters to query a device list.
Key | Type | Description |
---|---|---|
OR | [...value{string}] | List of OR identifiers |
IDeviceTokenModel
Properties in creating or updating a Device Token.
Key | Type | Description |
---|---|---|
name | string | This token is your access token key |
accessPermission | EAccessPermission | |
deviceTokenId | string | Record ID |
deviceAccessToken | string | This token is your access token key |
tunnelId | string | Tunnel ID this device is attached to |
staticTopics | IStaticTopic | |
lockTopics | boolean | Page number |
expireIn | integer | Expire in seconds from when the device token was created |
expireDate | integer | Calculated date of when this will happen |
loadBalance | ELoadBalanceType | Devices sharing the same device token will receive messages in a round robbin method |
IStaticTopic
Static Topics, are a group of Topic names and Identifiers. These are attached to a Device Token. In the scenario where the Device Token is locked, the Device only has access to its Static Topics.
Key | Type | Description |
---|---|---|
name | string | Topic name that static on the Device Token |
identifiers | [...value{string}] | Static identifiers |
IHttpPublish
Sending messages to the Message Broker via HTTP call
Key | Type | Description |
---|---|---|
data | ArrayBuffer | Data received from Topic subscription |
topicName | string | Topic name |
identifiers | string | List of NQL identifiers |
ITunnelQuery
Query parameters for Tunnel resource
Key | Type | Description |
---|---|---|
status | EStatus | Status of Tunnels |
size | number | Number of records in results |
page | number | Page to view |
search | string | Search for Tunnel name |
ITransport
Response received from Message Broker
Key | Type | Description |
---|---|---|
data | Uint8Array | Data received from Topic publish |
topicName | string | Topic name |
identifiers | [...value{string}] | Identifiers used for this received message |
presences | [...value{string}] | List of current active devices represented by custom data set |
ITunnelModel
Topic properties used to creating or updating a model
Key | Type | Description |
---|---|---|
tunnelId | string | Tunnel ID |
projectId | string | Topic name |
status | EStatus | Status of Tunnel |
name | string | Name of Tunnel |
sandbox | boolean | Sandbox or production Tunnel |
ITopicModel
Topic properties used to creating or updating a model
Key | Type | Description |
---|---|---|
topicId | string | Topic ID |
projectId | string | Topic name |
tunnelId | string | |
status | EStatus | Status of Topic |
name | string | Name of Topic |
triggerApi | ITopicApiModel | |
hydrateApi | ITopicApiModel | |
noEcho | boolean | Do not publish to Topic if device is also subscribed to the Topic |
ITopicApiModel
Advance websocket setup properties
Key | Type | Description |
---|---|---|
url | string | Data received from Topic subscription |
queryParams | object | URL query parameters |
headers | object | URL header parameters |
ITopicQuery
Query parameters available for a Topic
Key | Type | Description |
---|---|---|
topicId | string | |
projectId | string | |
tunnelId | string | |
status | EStatus | Status of Topics |
name | string | Topic name |
size | integer | Size of records returned |
page | integer | Current page number |
search | string | Search Topic name |
ITunnel
Query parameters available for a Topic
Key | Argument(s) | Type | Description |
---|---|---|---|
getTopic | topicName string |
ITopic | Get Topic instance |
subscribe | topicName string , identifiers string[] |
ITopic | Subscribe to a Topic |
unsubscribe | topicName string |
boolean | |
publish | topicName string , data ArrayBuffer , identifiers string[] |
void | Publish messages to Topic |
onReceive | callback(data ITransport) | void | Messages received on subscription |
onDisconnect | callback(errorMessage IErrorMessage) | void | Any errors encountred |
onReconnect | callback(data ITransport) | void | Subscriptions |
onErrors | callback(errorMessage IErrorMessage) | void | Any errors encountred |
disconnect | void | Disconnect from Tunnel |
ITopic
Query parameters available for a Topic
Key | Argument(s) | Type | Description |
---|---|---|---|
addIdentifiers | identifiers: INqlIdentifiers | ITopic | Get Topic instance |
removeIdentifiers | identifiers string[] |
ITopic | Subscribe to a Topic |
unsubscribe | boolean | ||
publish | data ArrayBuffer , identifiers string[] |
void | Publish messages to Topic |
onReceive | callback(data ITransport) | void | Messages received on subscription |
setPresence | presence string |
ITopic | Set data specific to device |
ITriggerRequest
List of field related error, it can also contain a nested list of error
Key | Type | Description |
---|---|---|
topicName | string | Topic name that triggered this Hydration |
identifiers | [...{string}] | List of identifiers attached to the Topic for tis Device |
data | string | Data triggered by this Topic trigger |
deviceId | string | UUID for the device making this request |
IHydrateRequest
Data sent to server on a Hydration request
Key | Type | Description |
---|---|---|
topicName | string | Topic name that triggered this Hydration |
identifiers | [...{string}] | List of identifiers attached to the Topic for tis Device |
deviceId | string | UUID for the device making this request |
IErrorMessage
Error model received from Message Broker or API
Key | Type | Description |
---|---|---|
id | string | ID for this error, can use this to find the issue |
code | integer | HTTP code associated with this error |
msg | string | Error message, explaining the HTTP status code received |
description | string | Additional information attached to the error |
errors | [...IErrorsModel] | If the error relates to field, errors, this ist will give more information on the error |
IErrorsModel
List of field related error, it can also contain a nested list of error
Key | Type | Description |
---|---|---|
property | string | Property that had the error |
value | string | Properties current value |
descriptions | string | What the error was on the property |
errors | [...IErrorsModel] or undefined |
Errors
Message Broker Errors
Error Code | Message | Description |
---|---|---|
401 | "Not authorized to use service." | User validation failed. |
404 | "Can not find resource" | Server can not find what you were looking for. |
disconnect | "Payload Too Large" | Payload sent to message broker exceeds Message Size. |
API Errors
The NoLag API uses the following error codes:
Error Code | Message | Description |
---|---|---|
400 | "Invalid request" | System does not understand request. |
401 | "Not authorized to use service." | User validation failed. |
403 | "Not allowed to access resource." | Not allowed to access resource. |
404 | "Can not find resource" | Server can not find what you were looking for. |
409 | "Duplicate resource found" | Resource already in system. |
500 | "System error" | Something within the system has hit a error. |