JavaScript 客户端库入门
按照此分步教程,使用 InfluxData 客户端库和您最喜欢的框架或语言构建物联网 (IoT) 应用程序。
在本教程中,您将使用 InfluxDB API 和客户端库构建现代应用程序,并学习以下内容
- InfluxDB 核心概念。
- 应用程序如何与设备和 InfluxDB 交互。
- 如何对应用和设备进行 API 身份验证。
- 如何安装客户端库。
- 如何在 InfluxDB 中写入和查询数据。
目录
- 目录
- 设置 InfluxDB
- IoT Starter 介绍
- 安装 Yarn
- 创建应用程序
- 安装 InfluxDB 客户端库
- 配置客户端库
- 构建 API
- 创建 API 以列出设备
- 创建 API 以注册设备
- 安装并运行 UI
设置 InfluxDB
如果您尚未执行此操作,请创建 InfluxDB Cloud 帐户或安装 InfluxDB OSS。
IoT Starter 示例应用假定以下先决条件
- InfluxDB org ID
- API 令牌(例如,具有存储桶的读取和写入权限的完全访问令牌)
- 一个名为
iot_center
的存储桶,用于存储来自设备的时间序列数据 - 一个名为
iot_center_devices
的存储桶,用于存储设备元数据和 API 令牌 ID
为生产应用使用受限令牌
对于生产应用程序,请创建并使用具有最小权限的读写令牌,并且仅将其用于单个客户端或应用程序。
IoT Starter 介绍
应用程序架构具有四个层
- InfluxDB API:InfluxDB v2 API。
- IoT 设备:虚拟或物理设备将 IoT 数据写入 InfluxDB API。
- UI:向服务器发送请求并在浏览器中呈现视图。
- API:接收来自 UI 的请求,向 InfluxDB 发送请求,并处理来自 InfluxDB 的响应。
有关本教程中引用的完整代码,请参阅 influxdata/iot-api-js 存储库。
安装 Yarn
如果您尚未安装 yarn
,请按照适用于您的 Node.js 版本的Yarn 包管理器安装说明进行操作。
要检查已安装的
yarn
版本,请在终端中输入以下代码yarn --version
创建应用程序
创建一个将包含您的 iot-api
项目的目录。以下示例代码在您的主目录中创建一个 iot-api
目录,并更改到新目录
mkdir ~/iot-api-apps
cd ~/iot-api-apps
按照以下步骤使用 Next.js 创建 JavaScript 应用程序
在您的
~/iot-api-apps
目录中,打开终端并输入以下命令以从 NextJS learn-starter 模板创建iot-api-js
应用yarn create-next-app iot-api-js --example "https://github.com/vercel/next-learn/tree/master/basics/learn-starter"
安装完成后,在终端中输入以下命令以进入您的
./iot-api-js
目录并启动开发服务器cd iot-api-js yarn dev -p 3001
要查看应用程序,请在浏览器中访问 http://localhost:3001。
安装 InfluxDB 客户端库
InfluxDB 客户端库提供以下 InfluxDB API 交互
- 使用 Flux 语言查询数据。
- 将数据写入 InfluxDB。
- 在后台批量处理数据。
- 在失败时自动重试请求。
在终端中输入以下命令以安装客户端库
yarn add @influxdata/influxdb-client
在终端中输入以下命令以安装
@influxdata/influxdb-client-apis
,即管理 API,用于创建、修改和删除授权、存储桶、任务以及其他 InfluxDB 资源yarn add @influxdata/influxdb-client-apis
有关客户端库的更多信息,请参阅 influxdata/influxdb-client-js 仓库。
配置客户端库
InfluxDB 客户端库需要来自您的 InfluxDB 环境的配置属性。通常,您会将以下属性作为应用程序的环境变量提供
INFLUX_URL
INFLUX_TOKEN
INFLUX_ORG
INFLUX_BUCKET
INFLUX_BUCKET_AUTH
Next.js 使用 env
模块为您的应用程序提供环境变量。
./.env.development
文件已版本化,包含用于开发环境的非机密默认设置。
# .env.development
INFLUX_URL=http://localhost:8086
INFLUX_BUCKET=iot_center
INFLUX_BUCKET_AUTH=iot_center_devices
要配置未添加到版本控制的密钥和设置,请创建一个 ./.env.local
文件并设置变量——例如,设置您的 InfluxDB 令牌和组织
# .env.local
# INFLUX_TOKEN
# InfluxDB API token used by the application server to send requests to InfluxDB.
# For convenience in development, use an **All Access** token.
INFLUX_TOKEN=29Xx1KH9VkASPR2DSfRfFd82OwGD...
# INFLUX_ORG
# InfluxDB organization ID you want to use in development.
INFLUX_ORG=48c88459ee424a04
在终端中输入以下命令以重启并加载 .env
文件
CONTROL+C
停止应用程序。yarn dev
启动应用程序。
Next.js 设置您可以在 process.env
对象中访问的变量——例如
console.log(process.env.INFLUX_ORG)
构建 API
您的应用程序 API 提供服务器端 HTTP 端点,用于处理来自 UI 的请求。每个 API 端点负责以下操作
- 监听 HTTP 请求(来自 UI)。
- 将请求转换为 InfluxDB API 请求。
- 处理 InfluxDB API 响应并处理错误。
- 使用状态和数据(对于 UI)进行响应。
创建 API 以列出设备
添加 /api/devices
API 端点,该端点检索、处理和列出设备。/api/devices
使用 /api/v2/query
InfluxDB API 端点查询 INFLUX_BUCKET_AUTH
以查找已注册的设备。
处理设备信息请求
创建
./pages/api/devices/[[...deviceParams]].js
文件以处理对/api/devices
和/api/devices/<deviceId>/measurements/
的请求。在该文件中,导出 Next.js 请求
handler
函数。请参阅示例。
在 Next.js 中,文件名模式 [[...param]].js
创建一个捕获所有 API 路由。要了解更多信息,请参阅 Next.js 动态 API 路由。
检索和列出设备
在 INFLUX_BUCKET_AUTH
中检索已注册的设备并处理查询结果。
创建一个 Flux 查询,该查询获取每个序列的最后一行,其中包含
deviceauth
测量。以下示例查询返回包含key
字段(授权 ID)的行,并排除包含token
字段的行(以避免向 UI 公开令牌)。// Flux query finds devices from(bucket:`${INFLUX_BUCKET_AUTH}`) |> range(start: 0) |> filter(fn: (r) => r._measurement == "deviceauth" and r._field != "token") |> last()
使用
QueryApi
客户端将 Flux 查询发送到POST /api/v2/query
InfluxDB API 端点。
创建包含以下内容的 ./pages/api/devices/_devices.js
文件
import { InfluxDB } from '@influxdata/influxdb-client'
import { flux } from '@influxdata/influxdb-client'
const INFLUX_ORG = process.env.INFLUX_ORG
const INFLUX_BUCKET_AUTH = process.env.INFLUX_BUCKET_AUTH
const influxdb = new InfluxDB({url: process.env.INFLUX_URL, token: process.env.INFLUX_TOKEN})
/**
* Gets devices or a particular device when deviceId is specified. Tokens
* are not returned unless deviceId is specified. It can also return devices
* with empty/unknown key, such devices can be ignored (InfluxDB authorization is not associated).
* @param deviceId optional deviceId
* @returns promise with an Record<deviceId, {deviceId, createdAt, updatedAt, key, token}>.
*/
export async function getDevices(deviceId) {
const queryApi = influxdb.getQueryApi(INFLUX_ORG)
const deviceFilter =
deviceId !== undefined
? flux` and r.deviceId == "${deviceId}"`
: flux` and r._field != "token"`
const fluxQuery = flux`from(bucket:${INFLUX_BUCKET_AUTH})
|> range(start: 0)
|> filter(fn: (r) => r._measurement == "deviceauth"${deviceFilter})
|> last()`
const devices = {}
return await new Promise((resolve, reject) => {
queryApi.queryRows(fluxQuery, {
next(row, tableMeta) {
const o = tableMeta.toObject(row)
const deviceId = o.deviceId
if (!deviceId) {
return
}
const device = devices[deviceId] || (devices[deviceId] = {deviceId})
device[o._field] = o._value
if (!device.updatedAt || device.updatedAt < o._time) {
device.updatedAt = o._time
}
},
error: reject,
complete() {
resolve(devices)
},
})
})
}
_devices
模块导出一个 getDevices(deviceId)
函数,该函数查询已注册的设备,处理数据,并返回带有结果的 Promise。如果您将该函数作为 getDevices()
(不带 deviceId
)调用,它将检索所有 deviceauth
点并返回带有 { DEVICE_ID: ROW_DATA }
的 Promise。
为了发送查询和处理结果,getDevices(deviceId)
函数使用 QueryAPI queryRows(query, consumer)
方法。queryRows
执行 query
并将带注释的 CSV 结果作为 Observable 提供给 consumer
。queryRows
具有以下 TypeScript 签名
queryRows(
query: string | ParameterizedQuery,
consumer: FluxResultObserver<string[]>
): void
您提供的 consumer
必须实现 FluxResultObserver
接口并提供以下回调函数
next(row, tableMeta)
:处理下一行和表格元数据——例如,准备响应。error(error)
:接收和处理错误——例如,通过拒绝 Promise。complete()
:在所有行都被使用后发出信号——例如,通过解析 Promise。
要了解有关 Observers 的更多信息,请参阅 RxJS 指南。
创建 API 以注册设备
在本应用程序中,已注册的设备是一个包含您的设备 ID、授权 ID 和 API 令牌的点。API 令牌和授权权限允许设备查询和写入 INFLUX_BUCKET
。在本节中,您将添加 API 端点,该端点处理来自 UI 的请求,在 InfluxDB 中创建授权,并将已注册的设备写入 INFLUX_BUCKET_AUTH
存储桶。要了解有关 API 令牌和授权的更多信息,请参阅 管理 API 令牌
应用程序 API 使用以下 /api/v2
InfluxDB API 端点
POST /api/v2/query
:查询INFLUX_BUCKET_AUTH
以查找已注册的设备。GET /api/v2/buckets
:获取INFLUX_BUCKET
的存储桶 ID。POST /api/v2/authorizations
:为设备创建授权。POST /api/v2/write
:将设备授权写入INFLUX_BUCKET_AUTH
。
添加
./pages/api/devices/create.js
文件以处理对/api/devices/create
的请求。在该文件中,导出执行以下操作的 Next.js 请求
handler
函数- 接受请求正文中的设备 ID。
- 查询
INFLUX_BUCKET_AUTH
,如果设备存在授权,则响应错误。 - 为设备创建授权.
- 将设备 ID 和授权写入
INFLUX_BUCKET_AUTH
. - 写入请求完成时,响应
HTTP 200
。
为设备创建授权
在本节中,您将创建一个具有对 INFLUX_BUCKET
的读-写权限的授权,并接收设备的 API 令牌。以下示例使用以下步骤创建授权
- 使用配置实例化
AuthorizationsAPI
客户端和BucketsAPI
客户端。 - 检索存储桶 ID。
- 使用客户端库向
/api/v2/authorizations
InfluxDB API 端点发送POST
请求。
在 ./api/devices/create.js
中,添加以下 createAuthorization(deviceId)
函数
import { InfluxDB } from '@influxdata/influxdb-client'
import { getDevices } from './_devices'
import { AuthorizationsAPI, BucketsAPI } from '@influxdata/influxdb-client-apis'
import { Point } from '@influxdata/influxdb-client'
const INFLUX_ORG = process.env.INFLUX_ORG
const INFLUX_BUCKET_AUTH = process.env.INFLUX_BUCKET_AUTH
const INFLUX_BUCKET = process.env.INFLUX_BUCKET
const influxdb = new InfluxDB({url: process.env.INFLUX_URL, token: process.env.INFLUX_TOKEN})
/**
* Creates an authorization for a supplied deviceId
* @param {string} deviceId client identifier
* @returns {import('@influxdata/influxdb-client-apis').Authorization} promise with authorization or an error
*/
async function createAuthorization(deviceId) {
const authorizationsAPI = new AuthorizationsAPI(influxdb)
const bucketsAPI = new BucketsAPI(influxdb)
const DESC_PREFIX = 'IoTCenterDevice: '
const buckets = await bucketsAPI.getBuckets({name: INFLUX_BUCKET, orgID: INFLUX_ORG})
const bucketId = buckets.buckets[0]?.id
return await authorizationsAPI.postAuthorizations(
{
body: {
orgID: INFLUX_ORG,
description: DESC_PREFIX + deviceId,
permissions: [
{
action: 'read',
resource: {type: 'buckets', id: bucketId, orgID: INFLUX_ORG},
},
{
action: 'write',
resource: {type: 'buckets', id: bucketId, orgID: INFLUX_ORG},
},
],
},
}
)
}
要创建具有对 INFLUX_BUCKET
的读-写权限的授权,您需要存储桶 ID。要检索存储桶 ID,createAuthorization(deviceId)
调用 BucketsAPI getBuckets
函数,该函数向 /api/v2/buckets
InfluxDB API 端点发送 GET
请求。然后,createAuthorization(deviceId)
在请求正文中传递新的授权,其中包含以下内容
- 存储桶 ID。
- 组织 ID。
- 描述:
IoTCenterDevice: DEVICE_ID
。 - 对存储桶的权限列表。
要了解有关 API 令牌和授权的更多信息,请参阅 管理 API 令牌。
接下来,将设备授权写入存储桶。
将设备授权写入存储桶
在 InfluxDB 中获得设备授权后,为设备写入一个点并将授权详细信息写入 INFLUX_BUCKET_AUTH
。将设备授权存储在存储桶中,您可以执行以下操作
- 报告设备授权历史记录。
- 管理带有和不带有令牌的设备。
- 将同一令牌分配给多个设备。
- 刷新令牌。
要将点写入 InfluxDB,请使用 InfluxDB 客户端库向 /api/v2/write
InfluxDB API 端点发送 POST
请求。在 ./pages/api/devices/create.js
中,添加以下 createDevice(deviceId)
函数
/** Creates an authorization for a deviceId and writes it to a bucket */
async function createDevice(deviceId) {
let device = (await getDevices(deviceId)) || {}
let authorizationValid = !!Object.values(device)[0]?.key
if(authorizationValid) {
console.log(JSON.stringify(device))
return Promise.reject('This device ID is already registered and has an authorization.')
} else {
console.log(`createDeviceAuthorization: deviceId=${deviceId}`)
const authorization = await createAuthorization(deviceId)
const writeApi = influxdb.getWriteApi(INFLUX_ORG, INFLUX_BUCKET_AUTH, 'ms', {
batchSize: 2,
})
const point = new Point('deviceauth')
.tag('deviceId', deviceId)
.stringField('key', authorization.id)
.stringField('token', authorization.token)
writeApi.writePoint(point)
await writeApi.close()
return
}
}
createDevice(device_id)
接受一个 device_id
并在以下步骤中将数据写入 INFLUX_BUCKET_AUTH
- 使用来自配置的
url
、token
和org
值初始化InfluxDBClient()
。 - 初始化
WriteAPI
客户端以将数据写入 InfluxDB 存储桶。 - 创建
Point
。 - 使用
writeApi.writePoint(point)
将Point
写入存储桶。
该函数写入具有以下元素的点
元素 | 名称 | 值 |
---|---|---|
测量 | 设备认证 | |
标签 | 设备ID | 设备 ID |
字段 | 键 | 授权 ID |
字段 | 令牌 | 授权 (API) 令牌 |
安装并运行 UI
influxdata/iot-api-ui
是一个独立的 Next.js React UI,它使用您的应用程序 API 在 InfluxDB 中写入和查询数据。iot-api-ui
使用 Next.js rewrites 将 /api/
路径中的所有请求路由到您的 API。
要安装和运行 UI,请执行以下操作
在您的
~/iot-api-apps
目录中,克隆influxdata/iot-api-ui
仓库 并进入iot-api-ui
目录,例如cd ~/iot-api-apps git clone git@github.com:influxdata/iot-api-ui.git cd ./iot-app-ui
./.env.development
文件包含您可以编辑或覆盖的默认配置设置(使用./.env.local
文件)。要启动 UI,请在您的终端中输入以下命令
yarn dev
要查看设备列表和注册设备,请在浏览器中访问 http://localhost:3000/devices。
要了解有关 UI 组件的更多信息,请参阅 influxdata/iot-api-ui
。
此页面是否对您有帮助?
感谢您的反馈!