JavaScript client library starter
This page documents an earlier version of InfluxDB. InfluxDB v2.7 is the latest stable version. View this page in the v2.7 documentation.
Follow this step-by-step tutorial to build an Internet-of-Things (IoT) application with InfluxData client libraries and your favorite framework or language.
In this tutorial, you’ll use the InfluxDB API and client libraries to build a modern application as you learn the following:
- InfluxDB core concepts.
- How the application interacts with devices and InfluxDB.
- How to authenticate apps and devices to the API.
- How to install a client library.
- How to write and query data in InfluxDB.
Contents
- Contents
- Set up InfluxDB
- Authenticate with an InfluxDB API token
- Introducing IoT Starter
- Create the application
- Install InfluxDB client library
- Configure the client library
- Build the API
- Create the API to list devices
- Handle requests for device information
- Retrieve and list devices
- Create the API to register devices
- Create an authorization for the device
- Write the device authorization to a bucket
- Install and run the UI
Set up InfluxDB
If you haven’t already, create an InfluxDB Cloud account or install InfluxDB OSS.
Authenticate with an InfluxDB API token
For convenience in development, create an All-Access token for your application. This grants your application full read and write permissions on all resources within your InfluxDB organization.
For a production application, create and use a read-write token with minimal permissions and only use it with your application.
Introducing IoT Starter
The application architecture has four layers:
- InfluxDB API: InfluxDB v2 API.
- IoT device: Virtual or physical devices write IoT data to the InfluxDB API.
- UI: Sends requests to the server and renders views in the browser.
- API: Receives requests from the UI, sends requests to InfluxDB, and processes responses from InfluxDB.
For the complete code referenced in this tutorial, see the influxdata/iot-api-js repository.
Install Yarn
If you haven’t already installed yarn, follow the Yarn package manager installation instructions for your version of Node.js.
- To check the installed
yarnversion, enter the following code into your terminal:
1. yarn --version
Create the application
Create a directory that will contain your iot-api projects. The following example code creates an iot-api directory in your home directory and changes to the new directory:
1. mkdir ~/iot-api-apps
2. cd ~/iot-api-apps
Follow these steps to create a JavaScript application with Next.js:
- In your
~/iot-api-appsdirectory, open a terminal and enter the following commands to create theiot-api-jsapp from the NextJS learn-starter template:
1. yarn create-next-app iot-api-js --example "https://github.com/vercel/next-learn/tree/master/basics/learn-starter"
2. After the installation completes, enter the following commands in your terminal to go into your ./iot-api-js directory and start the development server:
1. cd iot-api-js
2. yarn dev -p 3001
To view the application, visit <http://localhost:3001> in your browser.
Install InfluxDB client library
The InfluxDB client library provides the following InfluxDB API interactions:
- Query data with the Flux language.
- Write data to InfluxDB.
- Batch data in the background.
-
Retry requests automatically on failure.
-
Enter the following command into your terminal to install the client library:
1. yarn add @influxdata/influxdb-client
2. Enter the following command into your terminal to install @influxdata/influxdb-client-apis, the management APIs that create, modify, and delete authorizations, buckets, tasks, and other InfluxDB resources:
1. yarn add @influxdata/influxdb-client-apis
For more information about the client library, see the influxdata/influxdb-client-js repo.
Configure the client library
InfluxDB client libraries require configuration properties from your InfluxDB environment. Typically, you’ll provide the following properties as environment variables for your application:
INFLUX_URLINFLUX_TOKENINFLUX_ORGINFLUX_BUCKETINFLUX_BUCKET_AUTH
Next.js uses the env module to provide environment variables to your application.
The ./.env.development file is versioned and contains non-secret default settings for your development environment.
1. # .env.development
3. INFLUX_URL=http://localhost:8086
4. INFLUX_BUCKET=iot_center
5. INFLUX_BUCKET_AUTH=iot_center_devices
To configure secrets and settings that aren’t added to version control, create a ./.env.local file and set the variables–for example, set your InfluxDB token and organization:
1. # .env.local
3. # INFLUX_TOKEN
4. # InfluxDB API token used by the application server to send requests to InfluxDB.
5. # For convenience in development, use an **All-Access** token.
7. INFLUX_TOKEN=29Xx1KH9VkASPR2DSfRfFd82OwGD...
9. # INFLUX_ORG
10. # InfluxDB organization ID you want to use in development.
12. INFLUX_ORG=48c88459ee424a04
Enter the following commands into your terminal to restart and load the .env files:
CONTROL+Cto stop the application.yarn devto start the application.
Next.js sets variables that you can access in the process.env object–for example:
1. console.log(process.env.INFLUX_ORG)
Build the API
Your application API provides server-side HTTP endpoints that process requests from the UI. Each API endpoint is responsible for the following:
- Listen for HTTP requests (from the UI).
- Translate requests into InfluxDB API requests.
- Process InfluxDB API responses and handle errors.
- Respond with status and data (for the UI).
Create the API to list devices
Add the /api/devices API endpoint that retrieves, processes, and lists devices. /api/devices uses the /api/v2/query InfluxDB API endpoint to query INFLUX_BUCKET_AUTH for a registered device.
Handle requests for device information
- Create a
./pages/api/devices/[[...deviceParams]].jsfile to handle requests for/api/devicesand/api/devices/<deviceId>/measurements/. - In the file, export a Next.js request
handlerfunction. See the example.
In Next.js, the filename pattern [[...param]].js creates a catch-all API route. To learn more, see Next.js dynamic API routes.
Retrieve and list devices
Retrieve registered devices in INFLUX_BUCKET_AUTH and process the query results.
- Create a Flux query that gets the last row of each series that contains a
deviceauthmeasurement. The example query below returns rows that contain thekeyfield (authorization ID) and excludes rows that contain atokenfield (to avoid exposing tokens to the UI).
1. // Flux query finds devices
2. from(bucket:`${INFLUX_BUCKET_AUTH}`)
3. |> range(start: 0)
4. |> filter(fn: (r) => r._measurement == "deviceauth" and r._field != "token")
5. |> last()
2. Use the QueryApi client to send the Flux query to the POST /api/v2/query InfluxDB API endpoint.
Create a ./pages/api/devices/_devices.js file that contains the following:
1. import { InfluxDB } from '@influxdata/influxdb-client'
2. import { flux } from '@influxdata/influxdb-client'
4. const INFLUX_ORG = process.env.INFLUX_ORG
5. const INFLUX_BUCKET_AUTH = process.env.INFLUX_BUCKET_AUTH
6. const influxdb = new InfluxDB({url: process.env.INFLUX_URL, token: process.env.INFLUX_TOKEN})
8. /**
9. * Gets devices or a particular device when deviceId is specified. Tokens
10. * are not returned unless deviceId is specified. It can also return devices
11. * with empty/unknown key, such devices can be ignored (InfluxDB authorization is not associated).
12. * @param deviceId optional deviceId
13. * @returns promise with an Record<deviceId, {deviceId, createdAt, updatedAt, key, token}>.
14. */
15. export async function getDevices(deviceId) {
16. const queryApi = influxdb.getQueryApi(INFLUX_ORG)
17. const deviceFilter =
18. deviceId !== undefined
19. ? flux` and r.deviceId == "${deviceId}"`
20. : flux` and r._field != "token"`
21. const fluxQuery = flux`from(bucket:${INFLUX_BUCKET_AUTH})
22. |> range(start: 0)
23. |> filter(fn: (r) => r._measurement == "deviceauth"${deviceFilter})
24. |> last()`
25. const devices = {}
27. for await (const {row, tableMeta} of queryApi.iterateRows(fluxQuery)) {
28. const o = tableMeta.toObject(row)
29. const deviceId = o.deviceId
30. if (!deviceId) {
31. return
32. }
33. const device = devices[deviceId] || (devices[deviceId] = {deviceId})
34. device[o._field] = o._value
35. if (!device.updatedAt || device.updatedAt < o._time) {
36. device.updatedAt = o._time
37. }
38. }
40. return devices
41. }
iot-api-js/pages/api/devices/_devices.js getDevices(deviceId)
The _devices module exports a getDevices(deviceId) function that queries for registered devices, processes the data, and returns a Promise with the result. If you invoke the function as getDevices() (without a deviceId), it retrieves all deviceauth points and returns a Promise with { DEVICE_ID: ROW_DATA }.
To send the query and process results, the getDevices(deviceId) function uses the QueryAPI iterateRows(query) asynchronous method. iterateRows executes the query and provides the Annotated CSV result as an AsyncIterable. iterateRows has the following TypeScript signature:
1. iterateRows(
2. query: string | ParameterizedQuery
3. ): AsyncIterable<Row>
@influxdata/influxdb-client-js QueryAPI
Create the API to register devices
In this application, a registered device is a point that contains your device ID, authorization ID, and API token. The API token and authorization permissions allow the device to query and write to INFLUX_BUCKET. In this section, you add the API endpoint that handles requests from the UI, creates an authorization in InfluxDB, and writes the registered device to the INFLUX_BUCKET_AUTH bucket. To learn more about API tokens and authorizations, see Manage API tokens
The application API uses the following /api/v2 InfluxDB API endpoints:
POST /api/v2/query: to queryINFLUX_BUCKET_AUTHfor a registered device.GET /api/v2/buckets: to get the bucket ID forINFLUX_BUCKET.POST /api/v2/authorizations: to create an authorization for the device.-
POST /api/v2/write: to write the device authorization toINFLUX_BUCKET_AUTH. -
Add a
./pages/api/devices/create.jsfile to handle requests for/api/devices/create. -
In the file, export a Next.js request
handlerfunction that does the following: -
Accept a device ID in the request body.
- Query
INFLUX_BUCKET_AUTHand respond with an error if an authorization exists for the device. - Create an authorization for the device.
- Write the device ID and authorization to INFLUX_BUCKET_AUTH.
- Respond with
HTTP 200when the write request completes.
Create an authorization for the device
In this section, you create an authorization with read-write permission to INFLUX_BUCKET and receive an API token for the device. The example below uses the following steps to create the authorization:
- Instantiate the
AuthorizationsAPIclient andBucketsAPIclient with the configuration. - Retrieve the bucket ID.
- Use the client library to send a
POSTrequest to the/api/v2/authorizationsInfluxDB API endpoint.
In ./api/devices/create.js, add the following createAuthorization(deviceId) function:
1. import { InfluxDB } from '@influxdata/influxdb-client'
2. import { getDevices } from './_devices'
3. import { AuthorizationsAPI, BucketsAPI } from '@influxdata/influxdb-client-apis'
4. import { Point } from '@influxdata/influxdb-client'
6. const INFLUX_ORG = process.env.INFLUX_ORG
7. const INFLUX_BUCKET_AUTH = process.env.INFLUX_BUCKET_AUTH
8. const INFLUX_BUCKET = process.env.INFLUX_BUCKET
10. const influxdb = new InfluxDB({url: process.env.INFLUX_URL, token: process.env.INFLUX_TOKEN})
12. /**
13. * Creates an authorization for a supplied deviceId
14. * @param {string} deviceId client identifier
15. * @returns {import('@influxdata/influxdb-client-apis').Authorization} promise with authorization or an error
16. */
17. async function createAuthorization(deviceId) {
18. const authorizationsAPI = new AuthorizationsAPI(influxdb)
19. const bucketsAPI = new BucketsAPI(influxdb)
20. const DESC_PREFIX = 'IoTCenterDevice: '
22. const buckets = await bucketsAPI.getBuckets({name: INFLUX_BUCKET, orgID: INFLUX_ORG})
23. const bucketId = buckets.buckets[0]?.id
25. return await authorizationsAPI.postAuthorizations(
26. {
27. body: {
28. orgID: INFLUX_ORG,
29. description: DESC_PREFIX + deviceId,
30. permissions: [
31. {
32. action: 'read',
33. resource: {type: 'buckets', id: bucketId, orgID: INFLUX_ORG},
34. },
35. {
36. action: 'write',
37. resource: {type: 'buckets', id: bucketId, orgID: INFLUX_ORG},
38. },
39. ],
40. },
41. }
42. )
44. }
iot-api-js/pages/api/devices/create.js
To create an authorization that has read-write permission to INFLUX_BUCKET, you need the bucket ID. To retrieve the bucket ID, createAuthorization(deviceId) calls the BucketsAPI getBuckets function that sends a GET request to the /api/v2/buckets InfluxDB API endpoint. createAuthorization(deviceId) then passes a new authorization in the request body with the following:
- Bucket ID.
- Organization ID.
- Description:
IoTCenterDevice: DEVICE_ID. - List of permissions to the bucket.
To learn more about API tokens and authorizations, see Manage API tokens.
Next, write the device authorization to a bucket.
Write the device authorization to a bucket
With a device authorization in InfluxDB, write a point for the device and authorization details to INFLUX_BUCKET_AUTH. Storing the device authorization in a bucket allows you to do the following:
- Report device authorization history.
- Manage devices with and without tokens.
- Assign the same token to multiple devices.
- Refresh tokens.
To write a point to InfluxDB, use the InfluxDB client library to send a POST request to the /api/v2/write InfluxDB API endpoint. In ./pages/api/devices/create.js, add the following createDevice(deviceId) function:
1. /** Creates an authorization for a deviceId and writes it to a bucket */
2. async function createDevice(deviceId) {
3. let device = (await getDevices(deviceId)) || {}
4. let authorizationValid = !!Object.values(device)[0]?.key
5. if(authorizationValid) {
6. console.log(JSON.stringify(device))
7. return Promise.reject('This device ID is already registered and has an authorization.')
8. } else {
9. console.log(`createDeviceAuthorization: deviceId=${deviceId}`)
10. const authorization = await createAuthorization(deviceId)
11. const writeApi = influxdb.getWriteApi(INFLUX_ORG, INFLUX_BUCKET_AUTH, 'ms', {
12. batchSize: 2,
13. })
14. const point = new Point('deviceauth')
15. .tag('deviceId', deviceId)
16. .stringField('key', authorization.id)
17. .stringField('token', authorization.token)
18. writeApi.writePoint(point)
19. await writeApi.close()
20. return
21. }
22. }
iot-api-js/pages/api/devices/create.js
createDevice(device_id) takes a device_id and writes data to INFLUX_BUCKET_AUTH in the following steps:
- Initialize
InfluxDBClient()withurl,token, andorgvalues from the configuration. - Initialize a
WriteAPIclient for writing data to an InfluxDB bucket. - Create a
Point. - Use
writeApi.writePoint(point)to write thePointto the bucket.
The function writes a point with the following elements:
| Element | Name | Value |
|---|---|---|
| measurement | deviceauth |
|
| tag | deviceId |
device ID |
| field | key |
authorization ID |
| field | token |
authorization (API) token |
Install and run the UI
influxdata/iot-api-ui is a standalone Next.js React UI that uses your application API to write and query data in InfluxDB. iot-api-ui uses Next.js rewrites to route all requests in the /api/ path to your API.
To install and run the UI, do the following:
- In your
~/iot-api-appsdirectory, clone the influxdata/iot-api-ui repo and go into theiot-api-uidirectory–for example:
1. cd ~/iot-api-apps
2. git clone git@github.com:influxdata/iot-api-ui.git
3. cd ./iot-app-ui
2. The ./.env.development file contains default configuration settings that you can edit or override (with a ./.env.local file).
3. To start the UI, enter the following command into your terminal:
1. yarn dev
To view the list and register devices, visit <http://localhost:3000/devices> in your browser.
To learn more about the UI components, see influxdata/iot-api-ui.
