快速开始
本指南将帮助您在 5 分钟内完成第一个 OpenAPI 调用。我们推荐使用官方 SDK,它会自动处理认证、签名等复杂逻辑。
推荐使用 SDK
官方 SDK 已经封装了所有底层实现,开箱即用。如果您需要了解底层实现,请查看本文档末尾的"底层实现"章节。
前置要求
开始之前,请确保:
- ✅ 已获得 OpenAPI 使用权限(联系商务经理)
- ✅ 已获得以下凭证:
- App Code - 应用编码
- Access Key - 访问密钥
- Dataset Code - 数据集编码
- ✅ 已安装 Node.js 16+ 或 Bun
安装 SDK
npm install @lovrabet/sdk
# 或
bun add @lovrabet/sdk
场景 1: 服务端使用(Node.js/SSR)
适用于 Node.js 服务端、Next.js SSR、API 路由等场景。
基础用法
import { createClient } from "@lovrabet/sdk";
// 创建客户端(使用 accessKey)
const client = createClient({
appCode: "your-app-code",
accessKey: process.env.LOVRABET_ACCESS_KEY, // 从环境变量读取
models: {
users: {
tableName: "users",
datasetCode: "your-dataset-code",
},
},
});
// 查询数据列表
const response = await client.models.users.filter({
currentPage: 1,
pageSize: 20,
});
console.log("总条数:", response.paging.totalCount);
console.log("数据:", response.tableData);
// 查询单条数据
const user = await client.models.users.getOne("user-id");
console.log("用户详情:", user);
Next.js App Router 示例
在 Next.js 服务端组件中使用:
// app/users/page.tsx (Server Component)
import { createClient } from "@lovrabet/sdk";
const client = createClient({
appCode: process.env.LOVRABET_APP_CODE!,
accessKey: process.env.LOVRABET_ACCESS_KEY!,
models: {
users: {
tableName: "users",
datasetCode: process.env.LOVRABET_DATASET_CODE!,
},
},
});
export default async function UsersPage() {
// 直接在服务端组件中调用
const { tableData: users } = await client.models.users.filter({
pageSize: 10,
currentPage: 1,
});
return (
<div>
<h1>用户列表</h1>
{users.map((user) => (
<div key={user.id}>{user.name}</div>
))}
</div>
);
}
Next.js API 路由示例
创建 API 路由供前端调用:
// app/api/users/route.ts
import { createClient } from "@lovrabet/sdk";
import { NextResponse } from "next/server";
const client = createClient({
appCode: process.env.LOVRABET_APP_CODE!,
accessKey: process.env.LOVRABET_ACCESS_KEY!,
models: {
users: {
tableName: "users",
datasetCode: process.env.LOVRABET_DATASET_CODE!,
},
},
});
export async function GET(request: Request) {
try {
const { searchParams } = new URL(request.url);
const page = parseInt(searchParams.get("page") || "1");
const size = parseInt(searchParams.get("size") || "20");
const data = await client.models.users.filter({
currentPage: page,
pageSize: size,
});
return NextResponse.json(data);
} catch (error) {
return NextResponse.json({ error: "查询失败" }, { status: 500 });
}
}
场景 2: 浏览器端使用(预生成 Token)
适用于浏览器端公开数据访问、未登录用户等场景。
步骤 1: 服务端生成 Token
创建 API 路由生成 Token:
// app/api/token/route.ts
import { generateOpenApiToken } from "@lovrabet/sdk";
import { NextResponse } from "next/server";
export async function GET() {
try {
const result = await generateOpenApiToken({
appCode: process.env.LOVRABET_APP_CODE!,
datasetCode: process.env.LOVRABET_DATASET_CODE!,
accessKey: process.env.LOVRABET_ACCESS_KEY!,
});
// 返回 token、timestamp 和 expiresAt
return NextResponse.json(result);
} catch (error) {
return NextResponse.json({ error: "Token 生成失败" }, { status: 500 });
}
}
步骤 2: 浏览器使用 Token
// app/users/client-page.tsx
"use client";
import { createClient } from "@lovrabet/sdk";
import { useEffect, useState } from "react";
export default function ClientUsersPage() {
const [users, setUsers] = useState([]);
const [client, setClient] = useState(null);
useEffect(() => {
async function init() {
// 1. 获取 token
const { token, timestamp } = await fetch("/api/token").then((r) =>
r.json()
);
// 2. 创建客户端
const newClient = createClient({
appCode: "your-app-code",
token: token,
timestamp: timestamp,
models: {
users: {
tableName: "users",
datasetCode: "your-dataset-code",
},
},
});
setClient(newClient);
// 3. 查询数据
const { tableData } = await newClient.models.users.filter({
pageSize: 10,
});
setUsers(tableData);
}
init();
}, []);
return (
<div>
<h1>用户列表</h1>
{users.map((user) => (
<div key={user.id}>{user.name}</div>
))}
</div>
);
}
Token 自动刷新
Token 有效期为 10 分钟,需要定期刷新:
"use client";
import { createClient, isTokenExpiring } from "@lovrabet/sdk";
import { useEffect, useState } from "react";
export default function UsersWithRefresh() {
const [client, setClient] = useState(null);
const [timestamp, setTimestamp] = useState(null);
// 初始化客户端
useEffect(() => {
fetchTokenAndCreateClient();
}, []);
// Token 过期检查
useEffect(() => {
if (!timestamp) return;
const interval = setInterval(() => {
// 检查 Token 是否即将过期(提前 1 分钟刷新)
if (isTokenExpiring(timestamp, 60000)) {
console.log("Token 即将过期,刷新中...");
fetchTokenAndCreateClient();
}
}, 30000); // 每 30 秒检查一次
return () => clearInterval(interval);
}, [timestamp]);
async function fetchTokenAndCreateClient() {
const { token, timestamp: newTimestamp } = await fetch("/api/token").then(
(r) => r.json()
);
const newClient = createClient({
appCode: "your-app-code",
token: token,
timestamp: newTimestamp,
models: {
users: {
tableName: "users",
datasetCode: "your-dataset-code",
},
users: {
tableName: "users",
datasetCode: "your-dataset-code",
},
},
});
setClient(newClient);
setTimestamp(newTimestamp);
}
// ... 其他代码
}
场景 3: 浏览器端使用(Cookie 认证)
适用于已登录用户访问私有数据的场景。
"use client";
import { createClient } from "@lovrabet/sdk";
import { useEffect, useState } from "react";
export default function PrivateDataPage() {
const [data, setData] = useState([]);
useEffect(() => {
async function fetchData() {
// 不提供任何认证信息,自动使用浏览器 Cookie
const client = createClient({
appCode: "your-app-code",
models: {
orders: {
tableName: "orders",
datasetCode: "your-dataset-code",
},
},
});
// 请求会自动携带用户的登录 Cookie
const { tableData } = await client.models.orders.filter();
setData(tableData);
}
fetchData();
}, []);
return (
<div>
<h1>我的订单</h1>
{data.map((order) => (
<div key={order.id}>{order.orderNo}</div>
))}
</div>
);
}
多模型配置
一次性配置多个数据模型:
const client = createClient({
appCode: "your-app-code",
accessKey: process.env.LOVRABET_ACCESS_KEY,
models: {
users: {
tableName: "users",
datasetCode: "dataset-001",
},
orders: {
tableName: "orders",
datasetCode: "dataset-002",
},
products: {
tableName: "products",
datasetCode: "dataset-003",
},
},
});
// 使用不同的模型
const users = await client.models.users.filter();
const orders = await client.models.orders.filter();
const products = await client.models.products.filter();
高级查询
分页查询
const response = await client.models.users.filter({
currentPage: 2,
pageSize: 50,
});
console.log("当前页:", response.paging.currentPage);
console.log("每页条数:", response.paging.pageSize);
console.log("总条数:", response.paging.totalCount);
console.log("数据:", response.tableData);
条件筛选
const response = await client.models.users.filter({
currentPage: 1,
pageSize: 20,
// 其他查询条件会传递到 paramMap
status: "active",
role: "admin",
});
获取所有数据(分页遍历)
async function getAllUsers() {
const allUsers = [];
let currentPage = 1;
const pageSize = 50;
let hasMore = true;
while (hasMore) {
const response = await client.models.users.filter({
currentPage,
pageSize,
});
allUsers.push(...response.tableData);
// 判断是否还有更多数据
hasMore = currentPage * pageSize < response.paging.totalCount;
currentPage++;
// 避免请求过快
await new Promise((resolve) => setTimeout(resolve, 100));
}
return allUsers;
}
const allUsers = await getAllUsers();
console.log(`共获取 ${allUsers.length} 条数据`);
错误处理
import { createClient, LovrabetError } from "@lovrabet/sdk";
try {
const response = await client.models.users.filter();
console.log(response.tableData);
} catch (error) {
if (error instanceof LovrabetError) {
console.error("API 错误:", error.message);
console.error("状态码:", error.statusCode);
console.error("错误详情:", error.details);
} else {
console.error("未知错误:", error);
}
}
常见错误及解决方案
1. 签名验证失败
错误信息: errorCode: 1002, errorMsg: "签名验证失败"
解决方案:
- 检查 Access Key 是否正确
- 确保使用环境变量而非硬编码
- 验证 appCode 和 datasetCode 是否匹配
2. Token 过期
错误信息: errorCode: 1003, errorMsg: "时间戳过期"
解决方案:
- 确保客户端时间准确
- 在浏览器端实现 Token 自动刷新机制
- 使用
isTokenExpiring()检查 Token 有效期
3. 无访问权限
错误信息: errorCode: 1006, errorMsg: "无访问权限"
解决方案:
- 确认 Dataset Code 是否正确
- 检查应用是否有该数据集的访问权限
- 联系商务经理确认权限配置
环境配置
使用环境变量
创建 .env.local 文件:
LOVRABET_APP_CODE=your-app-code
LOVRABET_ACCESS_KEY=your-access-key
LOVRABET_DATASET_CODE=your-dataset-code
在代码中使用:
const client = createClient({
appCode: process.env.LOVRABET_APP_CODE!,
accessKey: process.env.LOVRABET_ACCESS_KEY!,
models: {
users: {
tableName: "users",
datasetCode: process.env.LOVRABET_DATASET_CODE!,
},
},
});
性能优化建议
1. 使用合理的分页大小
// ✅ 推荐:10-50 条
const response = await client.models.users.filter({
pageSize: 20,
});
// ❌ 避免:单次查询过多数据
const response = await client.models.users.filter({
pageSize: 1000, // 不推荐
});
2. 避免频繁调用 getOne
// ❌ 不推荐:循环调用 getOne
for (const id of userIds) {
const user = await client.models.users.getOne(id);
}
// ✅ 推荐:使用 getList 批量查询
const users = await client.models.users.filter({
id_in: userIds, // 假设支持 IN 查询
});
3. 实现缓存机制
const cache = new Map();
async function getCachedUsers() {
const cacheKey = "users-list";
if (cache.has(cacheKey)) {
const { data, timestamp } = cache.get(cacheKey);
// 缓存 1 分钟
if (Date.now() - timestamp < 60000) {
return data;
}
}
const data = await client.models.users.filter();
cache.set(cacheKey, { data, timestamp: Date.now() });
return data;
}
底层实现(高级)
仅供参考
以下是不使用 SDK 的底层实现方式。强烈推荐使用 SDK,除非您有特殊需求。
签名算法
import crypto from "crypto";
function generateToken(
timestamp: number,
appCode: string,
datasetCode: string,
accessKey: string,
secretKey: string = "lovrabet"
): string {
const params: Record<string, string> = {
accessKey: accessKey,
timeStamp: timestamp.toString(),
appCode: appCode,
};
if (datasetCode) {
params.datasetCode = datasetCode;
}
// 按字典序排序参数
const sortedParams = Object.keys(params)
.sort()
.map((key) => `${key}=${params[key]}`)
.join("&");
// 计算 HMAC-SHA256
return crypto
.createHmac("sha256", secretKey)
.update(sortedParams, "utf8")
.digest("base64");
}
原始 HTTP 请求
import axios from "axios";
async function getListRaw() {
const timestamp = Date.now();
const appCode = "your-app-code";
const datasetCode = "your-dataset-id";
const accessKey = "your-access-key";
const token = generateToken(timestamp, appCode, datasetCode, accessKey);
const response = await axios.post(
"https://runtime.lovrabet.com/openapi/data/get-list",
{
appCode: appCode,
datasetCode: datasetCode,
paramMap: {
pageSize: 10,
currentPage: 1,
},
},
{
headers: {
"Content-Type": "application/json",
"X-Time-Stamp": timestamp.toString(),
"X-App-Code": appCode,
"X-Dataset-Code": datasetCode,
"X-Token": token,
},
}
);
return response.data;
}
下一步
恭喜!您已经掌握了 Lovrabet OpenAPI 的基本用法。接下来:
需要帮助?
如遇到问题:
- 查看本文档的常见错误部分
- 查看 GitHub 仓库 的 Issues
- 联系商务经理获取技术支持