跳到主要内容

快速开始

本指南将帮助您在 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 的基本用法。接下来:

  • 认证指南 - 深入了解三种认证模式和 Token 管理
  • API 参考 - 查看完整的接口文档和高级功能

需要帮助?

如遇到问题:

  1. 查看本文档的常见错误部分
  2. 查看 GitHub 仓库 的 Issues
  3. 联系商务经理获取技术支持