JavaScript 客户端库入门
按照这个逐步教程,使用InfluxData客户端库和您喜欢的框架或语言构建一个物联网(IoT)应用程序。
在本教程中,您将使用InfluxDB API和客户端库来构建现代应用程序,同时学习以下内容:
- InfluxDB 核心概念。
- 应用程序如何与设备和InfluxDB交互。
- 如何对应用程序和设备进行API认证。
- 如何安装客户端库。
- 如何在InfluxDB中写入和查询数据。
目录
设置 InfluxDB
如果你还没有,创建一个 InfluxDB Cloud 帐户 或 安装 InfluxDB OSS。
物联网入门示例应用假设以下前提条件:
- 一个 InfluxDB org ID
- 一个 API token (例如,一个 完全访问令牌) 具有对存储桶的读取和写入权限
- 一个 bucket 名为
iot_center用于存储来自设备的时间序列数据 - 一个 bucket 名为
iot_center_devices用于存储设备元数据和API令牌ID
在生产应用中使用受限令牌
对于生产应用程序,创建并使用一个 读写 令牌,拥有最小的权限,并且仅在单个客户端或应用程序中使用它。
介绍IoT入门
应用程序架构分为四层:
- InfluxDB API: InfluxDB v2 API.
- IoT 设备: 虚拟或物理设备将 IoT 数据写入 InfluxDB API。
- 用户界面: 向服务器发送请求并在浏览器中渲染视图。
- API: 接收来自用户界面的请求,向InfluxDB发送请求,并处理来自InfluxDB的响应。
有关本教程中引用的完整代码,请参阅influxdata/iot-api-js repository。
安装Yarn
如果您尚未安装 yarn,请按照您版本的 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 template 创建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 repo。
配置客户端库
InfluxDB 客户端库需要来自您的 InfluxDB 环境的配置属性。通常,您将为您的应用程序提供以下属性作为环境变量:
INFLUX_URLINFLUX_TOKENINFLUX_ORGINFLUX_BUCKETINFLUX_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请求。
- 将请求转换为 InfluxDB API 请求。
- 处理InfluxDB API响应并处理错误。
- 响应状态和数据(用于用户界面)。
创建API以列出设备
添加 /api/devices API 端点,用于检索、处理和列出设备。
/api/devices 使用 /api/v2/query InfluxDB API 端点查询 INFLUX_BUCKET_AUTH 以获取注册设备。
处理设备信息请求
创建一个
./pages/api/devices/[[...deviceParams]].js文件来处理对/api/devices和/api/devices/的请求。/measurements/ 在文件中,导出一个 Next.js 请求
handler函数。查看示例。
在 Next.js 中,文件名模式 [[...param]].js 创建了一个 捕获所有 的 API 路由。 要了解更多,请参见 Next.js dynamic API routes。
检索和列出设备
检索注册的设备在 INFLUX_BUCKET_AUTH 并处理查询结果。
创建一个Flux查询,获取每个包含series的最后一行
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/queryInfluxDB 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点并返回一个Promise,格式为{ DEVICE_ID: ROW_DATA }。
要发送查询并处理结果,getDevices(deviceId) 函数使用 QueryAPI queryRows(query, consumer) 方法。
queryRows 执行 query 并将带注释的 CSV 结果作为可观察对象提供给 consumer。
queryRows 具有以下 TypeScript 签名:
queryRows(
query: string | ParameterizedQuery,
consumer: FluxResultObserver<string[]>
): void
您提供的 consumer 必须实现 FluxResultObserver 接口 并提供以下回调函数:
next(row, tableMeta): 处理下一行和表元数据——例如,准备响应。error(error): 接收和处理错误 - 例如,通过拒绝 Promise。complete(): 当所有行都被消耗时发出信号—例如,通过解析 Promise。
要了解更多关于观察者的内容,请参见RxJS指南。
创建注册设备的API
在这个应用中,注册设备 是一个包含您的设备ID、授权ID和API令牌的点。 API令牌和授权权限允许设备查询和写入INFLUX_BUCKET。 在这一部分,您添加处理来自UI请求的API端点,在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函数,它执行以下操作:- 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.
查看示例。
为设备创建授权
在本节中,您将创建对 INFLUX_BUCKET 的 读取-写入 权限的授权,并为设备接收一个 API 令牌。
下面的示例使用以下步骤来创建授权:
- 使用配置实例化
AuthorizationsAPI客户端和BucketsAPI客户端。 - 检索存储桶 ID。
- 使用客户端库向
/api/v2/authorizationsInfluxDB 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},
},
],
},
}
)
}
要创建一个具有 读-写 权限的授权,您需要桶 ID。
要检索桶 ID,
createAuthorization(deviceId) 调用 BucketsAPI getBuckets 函数,该函数发送一个 GET 请求到
/api/v2/buckets InfluxDB API 端点。
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写入桶中。
该函数写入一个包含以下元素的点:
| 元素 | 名称 | 值 |
|---|---|---|
| 测量 | deviceauth | |
| 标签 | deviceId | 设备 ID |
| 字段 | key | 授权ID |
| 字段 | token | 授权(API)令牌 |
安装并运行用户界面
influxdata/iot-api-ui 是一个独立的 Next.js React 用户界面,使用您的应用程序 API 向 InfluxDB 写入和查询数据。iot-api-ui 使用 Next.js rewrites 将所有请求路由到 /api/ 路径下的您的 API。
要安装和运行用户界面,请执行以下操作:
在你的
~/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文件)。要启动用户界面,请在终端中输入以下命令:
yarn dev要查看设备列表并注册设备,请在浏览器中访问 http://localhost:3000/devices。
要了解有关UI组件的更多信息,请参见 influxdata/iot-api-ui。