Skip to content

API 参考 ​

本文档提供 Lovrabet OpenAPI 所有接口的完整参考,包括 SDK 用法和底层 HTTP 规范。

基础信息 ​

环境地址 ​

环境域名
生产环境https://runtime.lovrabet.com

请求规范 ​

  • 请求方法: 所有接口统一使用 POST
  • 内容类型: application/json
  • 字符编码: UTF-8
  • 超时设置: 建议设置 30 秒超时

认证方式 ​

所有请求需要在 HTTP Header 中包含以下认证信息:

Header 名称说明示例
X-Time-Stamp时间戳(毫秒)1758903130713
X-App-Code应用编码app-c2dd52a2
X-Dataset-Code数据集编码(部分接口需要)0fefba76fe29...ff
X-Token签名 TokenjdqqGtzecF2I6FIW...

TIP

使用 SDKSDK 会自动添加所有必需的请求头,无需手动处理。

OpenAPI 接口列表 ​

完整接口清单 ​

以下是 Lovrabet OpenAPI 提供的所有接口及其详细信息:

接口名称HTTP 方法完整 URL 路径SDK 方法功能说明
批量查询数据POST/openapi/data/get-listfilter(params)分页查询数据,支持筛选、排序
查询单条数据POST/openapi/data/get-onegetOne(id)根据 ID 获取单条数据详情
创建数据POST/openapi/data/createcreate(data)创建新的数据记录
更新数据POST/openapi/data/updateupdate(id, data)更新已有数据记录
执行 SQLPOST/api/custom/executeSqlsql.execute(options)执行自定义 SQL 查询

INFO

功能限制OpenAPI 目前暂不支持 delete()、getSelectOptions() 和 excelExport() 操作。如需使用这些功能,请使用基于 Cookie 认证的 WebAPI 模式。

请求参数规范 ​

所有 OpenAPI 接口的请求体都遵循以下结构:

TypeScript
{
  appCode: string;           // 应用编码(所有接口必需)
  datasetCode: string;       // 数据集编码(所有数据操作接口都需要)
  paramMap: {                // 业务参数对象
    // 具体参数根据不同接口而定
  }
}

认证信息传递方式:

  • OpenAPI 的认证信息(不在请求体中),而是通过 HTTP Headers 传递:

    • X-Time-Stamp: 时间戳
    • X-App-Code: 应用编码
    • X-Dataset-Code: 数据集编码
    • X-Token: 签名 Token
  • SDK 会自动处理这些 Headers,开发者无需手动添加

各接口参数详解 ​

1. 批量查询数据 (getList) ​

URL: POST /openapi/data/get-list

请求体参数:

TypeScript
{
  appCode: string;
  datasetCode: string;
  paramMap: {
    currentPage?: number;     // 当前页码,从 1 开始
    pageSize?: number;        // 每页条数
    ytSortList?: SortList;    // 排序配置(通过 SDK 的 sortList 参数自动添加)
    [key: string]: any;       // 其他查询条件(根据数据集字段)
  }
}

参数说明:

参数名类型必填默认值说明
appCodestring✅ 是-应用编码
datasetCodestring✅ 是-数据集编码
paramMap.currentPagenumber❌ 否1当前页码,从 1 开始
paramMap.pageSizenumber❌ 否20每页记录数,最大 100
paramMap.ytSortListSortList❌ 否-排序配置数组,由 SDK 的 sortList 参数自动生成
paramMap.[字段名]any❌ 否-其他查询条件,根据数据集实际字段定义

查询条件示例:

根据数据集的不同字段,可以使用以下查询模式:

TypeScript
{
  // 精确匹配
  status: "active",
  customer_type: "vip",

  // 模糊查询(字段名加 _like 后缀)
  name_like: "张",

  // 范围查询(字段名加 _start/_end 后缀)
  create_time_start: "2024-01-01",
  create_time_end: "2024-12-31",
  amount_start: 1000,
  amount_end: 5000,

  // IN 查询(字段名加 _in 后缀,值为数组)
  status_in: ["active", "pending"],

  // IS NULL 查询(字段名加 _is_null 后缀)
  deleted_at_is_null: true,
}

排序功能 (ytSortList):

OpenAPI 使用 ytSortList 字段进行排序,通过 SDK 的 sortList 参数传入:

TypeScript
import { SortOrder } from "@lovrabet/sdk";

// SDK 调用方式(推荐)
const result = await client.models.users.filter(
  { currentPage: 1, pageSize: 20 },
  [
    { priority: SortOrder.DESC }, // 优先级降序
    { createTime: SortOrder.DESC }, // 创建时间降序
    { name: SortOrder.ASC }, // 名称升序
  ]
);

// SDK 会自动将 sortList 转换为 ytSortList 字段放到 paramMap 中
// 实际请求体: { appCode, datasetCode, paramMap: { ytSortList: [...] } }

TIP

排序说明

  • OpenAPI 只支持通过 ytSortList 字段排序
  • 使用 SDK 时,通过 getList() 方法的第二个参数 sortList 传入排序配置
  • SDK 会自动将 sortList 转换为 ytSortList 格式

响应数据 (data 字段):

TypeScript
{
  paging: {
    pageSize: number; // 每页记录数
    totalCount: number; // 总记录数
    currentPage: number; // 当前页码
  }
  tableData: Array<T>; // 数据列表数组
  tableColumns: Array<{
    title: string; // 列标题
    dataIndex: string; // 字段名
  }>;
}

2. 查询单条数据 (getOne) ​

URL: POST /openapi/data/get-one

请求体参数:

TypeScript
{
  appCode: string;
  datasetCode: string;
  paramMap: {
    id: string | number; // 记录 ID
  }
}

参数说明:

参数名类型必填说明
appCodestring✅ 是应用编码
datasetCodestring✅ 是数据集编码
paramMap.idstring/number✅ 是要查询的记录 ID

响应数据 (data 字段):

TypeScript
{
  id: string | number;     // 记录 ID
  [key: string]: any;      // 其他字段根据数据集定义
}

3. 创建数据 (create) ​

URL: POST /openapi/data/create

请求体参数:

TypeScript
{
  appCode: string;
  datasetCode: string;
  paramMap: {
    [key: string]: any;   // 要创建的数据字段
  }
}

参数说明:

参数名类型必填说明
appCodestring✅ 是应用编码
datasetCodestring✅ 是数据集编码
paramMap.[字段名]any根据字段定义要创建的数据,字段和必填性根据数据集定义

注意事项:

  • 系统字段(如 id, gmt_create, gmt_modified)会自动生成,无需传入
  • 必填字段必须提供,否则会返回参数错误
  • 字段类型需要与数据集定义一致

响应数据 (data 字段):

TypeScript
{
  id: string | number;     // 新创建记录的 ID
  [key: string]: any;      // 完整的记录数据(包括自动生成的字段)
}

4. 更新数据 (update) ​

URL: POST /openapi/data/update

请求体参数:

TypeScript
{
  appCode: string;
  datasetCode: string;
  paramMap: {
    id: string | number;  // 要更新的记录 ID
    [key: string]: any;   // 要更新的字段
  }
}

参数说明:

参数名类型必填说明
appCodestring✅ 是应用编码
datasetCodestring✅ 是数据集编码
paramMap.idstring/number✅ 是要更新的记录 ID
paramMap.[字段名]any❌ 否要更新的字段,只需传入需要更新的字段即可(部分更新)

注意事项:

  • 支持部分更新,只需传入要修改的字段
  • gmt_modified 字段会自动更新
  • 不能修改 id 和 gmt_create 字段

响应数据 (data 字段):

TypeScript
{
  id: string | number;     // 记录 ID
  [key: string]: any;      // 完整的更新后记录数据
}

响应结构 ​

通用响应格式 ​

所有接口响应都包含以下顶层字段(由平台网关返回):

TypeScript
{
  success: boolean;      // 请求是否成功
  msg: string;           // 响应消息
  data: any;             // 响应数据
  errorCode?: number;    // 错误码(失败时返回)
  errorMsg?: string;     // 错误信息(失败时返回)
}

getList 响应的固定字段 ​

getList 接口的 data 字段包含以下三个固定字段(SDK 返回结构与平台一致):

TypeScript
{
  paging: {
    // 【固定字段】分页信息
    pageSize: number; // 每页记录数
    totalCount: number; // 总记录数
    currentPage: number; // 当前页码
  }
  tableData: Array<T>; // 【固定字段】数据列表数组
  tableColumns: Array<{
    // 【固定字段】表格列定义
    title: string; // 列标题
    dataIndex: string; // 字段名
  }>;
}

SDK 使用 ​

创建客户端 ​

TypeScript
import { createClient } from "@lovrabet/sdk";

const client = createClient({
  appCode: "your-app-code",
  accessKey: process.env.LOVRABET_ACCESS_KEY,
  models: {
    users: {
      tableName: "users",
      datasetCode: "your-dataset-code",
    },
  },
});

SDK 方法列表 ​

每个模型实例都提供以下方法:

方法说明对应 API
getList(params?)批量查询数据/openapi/data/get-list
getOne(id)查询单条数据/openapi/data/get-one
create(data)新增单条数据/openapi/data/create
update(id, data)更新单条数据/openapi/data/update

SQL 执行 ​

OpenAPI 模式支持执行自定义 SQL 查询,适用于复杂报表、多表关联等场景。

基本用法 ​

TypeScript
// 执行 SQL 查询
const result = await client.sql.execute({
  sqlCode: 'your-sql-code',  // SQL 代码标识
  params: {                  // 可选:SQL 参数
    startDate: '2024-01-01',
    endDate: '2024-12-31'
  }
});

// 检查执行结果
if (result.execSuccess) {
  console.log('查询结果:', result.execResult);
} else {
  console.error('执行失败:', result.execError);
}

带类型安全的调用 ​

TypeScript
interface MonthlyStats {
  customer_name: string;
  total_amount: number;
  order_count: number;
}

const result = await client.sql.execute<MonthlyStats>({
  sqlCode: 'monthly-sales-stats',
  params: { year: 2024 }
});

if (result.execSuccess && result.execResult) {
  result.execResult.forEach(stat => {
    console.log(`${stat.customer_name}: ${stat.total_amount}元`);
  });
}

安全执行方式(推荐) ​

使用 sqlSafe 包装器简化错误处理:

TypeScript
import { sqlSafe } from "@lovrabet/sdk";

const { data, error } = await sqlSafe(() =>
  client.sql.execute({
    sqlCode: 'customer-orders',
    params: { customerId: '123' }
  })
);

if (error) {
  console.error('查询失败:', error.message);
  return;
}

// data 直接是查询结果数组
console.log('订单数量:', data.length);

返回值结构 ​

TypeScript
interface SqlExecuteResult<T> {
  execSuccess: boolean;  // SQL 执行是否成功
  execResult?: T[];      // 查询结果数组(成功时)
  execError?: string;    // 错误信息(失败时)
}

TIP

使用场景

  • 复杂的多表关联查询
  • 聚合统计报表
  • 不适合用 filter 表达的复杂条件
  • 需要优化的高性能查询

INFO

SQL 管理自定义 SQL 需要在 Lovrabet 平台上预先创建和配置。你可以通过 MCP 工具或平台界面管理 SQL 查询。

API 详细说明 ​

1. 批量查询数据(getList) ​

分页查询数据集中的数据,支持条件筛选、排序等功能。

SDK 用法 ​

基础查询:

TypeScript
const response = await client.models.users.filter({
  currentPage: 1,
  pageSize: 20,
});

// 解构响应
const { paging, tableData, tableColumns } = response;

console.log("总条数:", paging.totalCount);
console.log("当前页:", paging.currentPage);
console.log("数据:", tableData);
console.log("列定义:", tableColumns);

条件查询:

TypeScript
const response = await client.models.users.filter({
  currentPage: 1,
  pageSize: 20,
  // 查询条件(根据数据集实际字段)
  status: "active",
  customer_type: "vip",
});

分页遍历:

TypeScript
async function getAllUsers() {
  const allUsers = [];
  let currentPage = 1;
  const pageSize = 50;

  while (true) {
    const { paging, tableData } = await client.models.users.filter({
      currentPage,
      pageSize,
    });

    allUsers.push(...tableData);

    // 判断是否还有更多数据
    if (currentPage * pageSize >= paging.totalCount) {
      break;
    }

    currentPage++;

    // 避免请求过快
    await new Promise((resolve) => setTimeout(resolve, 100));
  }

  return allUsers;
}

HTTP 规范 ​

接口地址: POST /openapi/data/get-list

请求头:

Plain
X-Time-Stamp: {timestamp}
X-App-Code: {appCode}
X-Dataset-Code: {datasetCode}
X-Token: {token}

请求体:

JSON
{
  "appCode": "app-c2dd52a2",
  "datasetCode": "0fefba76fe29440194841f4825df53ff",
  "paramMap": {
    "pageSize": 10,
    "currentPage": 1,
    "status": "active",
    "customer_type": "vip",
    "create_time_start": "2024-01-01",
    "create_time_end": "2024-12-31"
  }
}

带排序的请求体示例:

JSON
{
  "appCode": "app-c2dd52a2",
  "datasetCode": "0fefba76fe29440194841f4825df53ff",
  "paramMap": {
    "pageSize": 10,
    "currentPage": 1,
    "ytSortList": [{ "gmt_create": "desc" }, { "id": "asc" }],
    "status": "active"
  }
}

响应结构说明:

data 字段下包含三个固定字段:

  • paging - 分页信息(固定字段)
  • tableData - 数据列表(固定字段)
  • tableColumns - 表格列定义(固定字段)

响应示例:

JSON
{
  "success": true,
  "msg": "查询成功",
  "data": {
    "paging": {
      "pageSize": 10,
      "totalCount": 156,
      "currentPage": 1
    },
    "tableData": [
      {
        "id": "123",
        "customer_name": "示例客户",
        "customer_type": "vip",
        "contact_person": "张三",
        "phone": "13800138000",
        "email": "example@example.com",
        "address": "北京市朝阳区",
        "status": "active",
        "credit_level": "A",
        "gmt_create": "2024-01-15 10:30:00",
        "gmt_modified": "2024-03-20 14:25:00"
      }
    ],
    "tableColumns": [
      {
        "title": "客户名称",
        "dataIndex": "customer_name"
      },
      {
        "title": "客户类型",
        "dataIndex": "customer_type"
      },
      {
        "title": "联系人",
        "dataIndex": "contact_person"
      }
    ]
  }
}

查询参数详解 ​

分页参数:

参数类型必须默认值说明
pageSizenumber否10每页记录数,最大 100
currentPagenumber否1当前页码,从 1 开始

排序参数:

参数类型必须说明
ytSortListArray否排序配置数组,格式: [{ "字段名": "asc/desc" }]

TIP

排序使用方式使用 SDK 时通过 getList() 的第二个参数传入 sortList,SDK 会自动转换为 ytSortList 字段。详见上方"排序功能"章节的说明。

条件查询:

条件查询参数根据不同数据集的字段而定,常见的查询方式:

TypeScript
{
  // 精确匹配
  field_name: "value",

  // 模糊查询(部分字段支持)
  field_name_like: "value",

  // 范围查询
  field_name_start: "value1",
  field_name_end: "value2",

  // IN 查询(部分字段支持)
  field_name_in: ["value1", "value2"],

  // NULL 判断(部分字段支持)
  field_name_is_null: true,
}

2. 查询单条数据(getOne) ​

根据唯一标识查询单条详细数据。

SDK 用法 ​

TypeScript
// 查询单条数据
const user = await client.models.users.getOne("user-id");

console.log(user);
// 返回单个对象,包含该记录的所有字段

// 或者使用对象参数
const user = await client.models.users.getOne({
  id: 14,
});

HTTP 规范 ​

接口地址: POST /openapi/data/get-one

请求头:

Plain
X-Time-Stamp: {timestamp}
X-App-Code: {appCode}
X-Dataset-Code: {datasetCode}
X-Token: {token}

请求体:

JSON
{
  "appCode": "app-c2dd52a2",
  "datasetCode": "0fefba76fe29440194841f4825df53ff",
  "paramMap": {
    "id": 14
  }
}

响应示例:

JSON
{
  "success": true,
  "msg": "查询成功",
  "data": {
    "id": 14,
    "customer_name": "示例客户",
    "customer_type": "vip",
    "contact_person": "张三",
    "phone": "13800138000",
    "email": "example@example.com",
    "address": "北京市朝阳区XX路XX号",
    "status": "active",
    "credit_level": "A",
    "credit_amount": 100000.0,
    "used_amount": 35000.0,
    "available_amount": 65000.0,
    "contract_start": "2024-01-01",
    "contract_end": "2024-12-31",
    "sales_person": "王经理",
    "department": "华北销售部",
    "gmt_create": "2024-01-15 10:30:00",
    "gmt_modified": "2024-03-20 14:25:00",
    "remark": "重要VIP客户,需重点维护"
  }
}

3. 新增单条数据(create) ​

创建一条新的数据记录。

SDK 用法 ​

TypeScript
// 新增客户信息
const newCustomer = await client.models.users.create({
  customer_name: "新客户公司",
  customer_type: "enterprise",
  contact_person: "李经理",
  phone: "13900139000",
  email: "contact@newcustomer.com",
  address: "上海市浦东新区",
  status: "active",
  credit_level: "B",
});

console.log("新客户 ID:", newCustomer.id);
console.log("创建时间:", newCustomer.gmt_create);

HTTP 规范 ​

接口地址: POST /openapi/data/create

请求头:

Plain
X-Time-Stamp: {timestamp}
X-App-Code: {appCode}
X-Dataset-Code: {datasetCode}
X-Token: {token}

请求体:

JSON
{
  "appCode": "app-c2dd52a2",
  "datasetCode": "0fefba76fe29440194841f4825df53ff",
  "paramMap": {
    "customer_name": "新客户公司",
    "customer_type": "enterprise",
    "contact_person": "李经理",
    "phone": "13900139000",
    "email": "contact@newcustomer.com",
    "address": "上海市浦东新区",
    "status": "active",
    "credit_level": "B"
  }
}

响应示例:

JSON
{
  "success": true,
  "msg": "创建成功",
  "data": {
    "id": 158,
    "customer_name": "新客户公司",
    "customer_type": "enterprise",
    "contact_person": "李经理",
    "phone": "13900139000",
    "email": "contact@newcustomer.com",
    "address": "上海市浦东新区",
    "status": "active",
    "credit_level": "B",
    "credit_amount": 0.0,
    "used_amount": 0.0,
    "available_amount": 0.0,
    "gmt_create": "2025-10-10 15:30:00",
    "gmt_modified": "2025-10-10 15:30:00"
  }
}

4. 更新单条数据(update) ​

根据 ID 更新已有数据记录的部分或全部字段。

SDK 用法 ​

TypeScript
// 更新客户信息
const updatedCustomer = await client.models.users.update(158, {
  customer_type: "vip",
  credit_level: "A",
  credit_amount: 200000.0,
  remark: "升级为 VIP 客户,提升信用额度",
});

console.log("更新后的客户类型:", updatedCustomer.customer_type);
console.log("更新时间:", updatedCustomer.gmt_modified);

批量更新示例:

TypeScript
// 批量更新多个客户的状态
const customerIds = [101, 102, 103];

const updateResults = await Promise.all(
  customerIds.map((id) =>
    client.models.users.update(id, {
      status: "inactive",
      remark: "批量停用",
    })
  )
);

console.log(`成功更新 ${updateResults.length} 个客户`);

HTTP 规范 ​

接口地址: POST /openapi/data/update

请求头:

Plain
X-Time-Stamp: {timestamp}
X-App-Code: {appCode}
X-Dataset-Code: {datasetCode}
X-Token: {token}

请求体:

JSON
{
  "appCode": "app-c2dd52a2",
  "datasetCode": "0fefba76fe29440194841f4825df53ff",
  "paramMap": {
    "id": 158,
    "customer_type": "vip",
    "credit_level": "A",
    "credit_amount": 200000.0,
    "remark": "升级为 VIP 客户,提升信用额度"
  }
}

响应示例:

JSON
{
  "success": true,
  "msg": "更新成功",
  "data": {
    "id": 158,
    "customer_name": "新客户公司",
    "customer_type": "vip",
    "contact_person": "李经理",
    "phone": "13900139000",
    "email": "contact@newcustomer.com",
    "address": "上海市浦东新区",
    "status": "active",
    "credit_level": "A",
    "credit_amount": 200000.0,
    "used_amount": 0.0,
    "available_amount": 200000.0,
    "gmt_create": "2025-10-10 15:30:00",
    "gmt_modified": "2025-10-10 16:45:00",
    "remark": "升级为 VIP 客户,提升信用额度"
  }
}

软删除建议

OpenAPI 目前不提供物理删除接口。如需删除数据,建议使用"软删除"方式,即通过 update() 方法更新状态字段:

TypeScript
// 推荐:使用软删除(更新状态为 deleted)
await client.models.users.update(158, {
  status: "deleted",
  deleted_at: new Date().toISOString(),
  remark: "客户要求删除数据",
});

console.log("客户已标记为删除");

软删除的优势:

  • ✅ 数据可恢复
  • ✅ 保留操作记录
  • ✅ 符合数据合规要求

错误处理 ​

错误码说明 ​

当请求失败时,success 字段为 false,并返回相应的错误码和错误信息。

错误码说明解决方案
1001参数错误检查请求参数是否完整、格式是否正确
1002签名验证失败检查 Access Key、签名算法、时间戳
1003时间戳过期Token 已过期(10 分钟),重新生成
1004应用不存在检查 App Code 是否正确
1005数据集不存在检查 Dataset Code 是否正确
1006无访问权限确认应用是否有该数据集的访问权限
2001查询超时优化查询条件,减少数据量
2002数据不存在检查查询条件或 ID 是否正确
3001服务器内部错误联系技术支持
4001请求频率超限降低请求频率,实施限流策略

错误响应示例 ​

JSON
{
  "success": false,
  "msg": null,
  "data": null,
  "errorCode": 1002,
  "errorMsg": "签名验证失败,请检查 Token 生成算法"
}

SDK 错误处理 ​

TypeScript
import { LovrabetError } from "@lovrabet/sdk";

try {
  const users = await client.models.users.filter();
} catch (error) {
  if (error instanceof LovrabetError) {
    console.error("错误码:", error.statusCode);
    console.error("错误信息:", error.message);
    console.error("错误详情:", error.details);

    // 根据错误码处理
    switch (error.statusCode) {
      case 1002:
        console.error("签名验证失败,请检查 Access Key");
        break;
      case 1003:
        console.error("Token 已过期,需要刷新");
        break;
      case 1006:
        console.error("无权访问该数据集");
        break;
      default:
        console.error("其他错误");
    }
  } else {
    console.error("未知错误:", error);
  }
}

高级用法 ​

1. TypeScript 类型支持 ​

TypeScript
import { createClient, ListResponse } from "@lovrabet/sdk";

// 定义数据类型
interface User {
  id: string;
  name: string;
  email: string;
  status: "active" | "inactive";
  gmt_create: string;
}

const client = createClient({
  // ... 配置
});

// 类型化查询
const response: ListResponse<User> = await client.models.users.filter();

response.tableData.forEach((user: User) => {
  console.log(user.name, user.email);
});

2. 多模型配置 ​

TypeScript
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();

3. 响应数据转换 ​

TypeScript
const response = await client.models.users.filter();

// 提取纯数据数组
const users = response.tableData;

// 提取列定义(用于动态构建表格 UI)
const columns = response.tableColumns.map((col) => ({
  title: col.title,
  field: col.dataIndex,
}));

// 分页信息
const { totalCount, currentPage, pageSize } = response.paging;
const totalPages = Math.ceil(totalCount / pageSize);

4. 请求拦截和日志 ​

TypeScript
import { createClient } from "@lovrabet/sdk";

const client = createClient({
  appCode: "your-app-code",
  accessKey: process.env.LOVRABET_ACCESS_KEY,
  models: {
    /* ... */
  },
});

// 包装请求方法添加日志
const originalGetList = client.models.users.getList.bind(client.models.users);

client.models.users.getList = async function (params) {
  console.log("请求参数:", params);
  const startTime = Date.now();

  try {
    const result = await originalGetList(params);
    console.log("请求成功,耗时:", Date.now() - startTime, "ms");
    return result;
  } catch (error) {
    console.error("请求失败:", error);
    throw error;
  }
};

性能优化 ​

1. 分页查询建议 ​

TypeScript
// ✅ 推荐:合理的分页大小
const response = await client.models.users.filter({
  pageSize: 20, // 10-50 条较合适
});

// ❌ 避免:单次查询过多数据
const response = await client.models.users.filter({
  pageSize: 1000, // 不推荐,影响性能
});

2. 避免 N+1 查询 ​

TypeScript
// ❌ 不推荐:循环调用 getOne
for (const id of userIds) {
  const user = await client.models.users.getOne(id);
  // 处理 user
}

// ✅ 推荐:使用 getList 批量查询
const users = await client.models.users.filter({
  id_in: userIds, // 假设支持 IN 查询
});

3. 实现缓存 ​

TypeScript
class CachedApiClient {
  private cache = new Map<string, { data: any; timestamp: number }>();
  private cacheTTL = 60000; // 1 分钟

  async getListCached(params: any) {
    const cacheKey = JSON.stringify(params);
    const cached = this.cache.get(cacheKey);

    if (cached && Date.now() - cached.timestamp < this.cacheTTL) {
      return cached.data;
    }

    const data = await client.models.users.filter(params);
    this.cache.set(cacheKey, { data, timestamp: Date.now() });

    return data;
  }
}

4. 并发控制 ​

TypeScript
// 限制并发数
async function batchQuery(ids: string[], concurrency = 3) {
  const results = [];

  for (let i = 0; i < ids.length; i += concurrency) {
    const batch = ids.slice(i, i + concurrency);
    const batchResults = await Promise.all(
      batch.map((id) => client.models.users.getOne(id))
    );
    results.push(...batchResults);
  }

  return results;
}

请求限制 ​

频率限制 ​

限制类型限制值
每分钟600 次请求
每小时10,000 次请求
每天100,000 次请求

数据量限制 ​

限制类型限制值
单次查询最多返回100 条记录
响应体最大10MB
请求体最大1MB

并发限制 ​

限制类型限制值
每个应用最多并发连接10 个

TIP

性能建议

  • 使用连接池管理请求
  • 实现请求队列和限流机制
  • 合理设置超时时间

原始 HTTP 请求(高级) ​

INFO

仅供参考推荐使用 SDK,以下内容仅供需要底层实现的开发者参考。

签名生成 ​

TypeScript
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 请求示例 ​

TypeScript
async function getListRaw() {
  const timestamp = Date.now();
  const appCode = "app-c2dd52a2";
  const datasetCode = "0fefba76fe29440194841f4825df53ff";
  const accessKey = "your-access-key";

  const token = generateToken(timestamp, appCode, datasetCode, accessKey);

  const response = await fetch(
    "https://runtime.lovrabet.com/openapi/data/get-list",
    {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "X-Time-Stamp": timestamp.toString(),
        "X-App-Code": appCode,
        "X-Dataset-Code": datasetCode,
        "X-Token": token,
      },
      body: JSON.stringify({
        appCode: appCode,
        datasetCode: datasetCode,
        paramMap: {
          pageSize: 10,
          currentPage: 1,
        },
      }),
    }
  );

  return await response.json();
}

最佳实践 ​

1. 错误处理和重试 ​

TypeScript
async function apiCallWithRetry(
  fn: () => Promise<any>,
  maxRetries = 3,
  delay = 1000
) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (error instanceof LovrabetError) {
        // Token 过期可以重试
        if (error.statusCode === 1003 && i < maxRetries - 1) {
          await new Promise((resolve) => setTimeout(resolve, delay));
          continue;
        }
      }
      throw error;
    }
  }
}

// 使用
const users = await apiCallWithRetry(() => client.models.users.filter());

2. 日志记录 ​

TypeScript
function logApiCall(
  method: string,
  params: any,
  result: any,
  duration: number
) {
  console.log({
    timestamp: new Date().toISOString(),
    method: method,
    params: params,
    success: true,
    duration: duration,
    recordCount: result.tableData?.length || 0,
  });
}

3. 监控和告警 ​

TypeScript
class ApiMonitor {
  private errorCount = 0;
  private errorThreshold = 10;

  async callWithMonitoring(fn: () => Promise<any>) {
    try {
      const result = await fn();
      this.errorCount = 0; // 重置错误计数
      return result;
    } catch (error) {
      this.errorCount++;

      if (this.errorCount >= this.errorThreshold) {
        // 触发告警
        this.sendAlert("API 错误率过高");
      }

      throw error;
    }
  }

  private sendAlert(message: string) {
    // 发送告警通知
    console.error("告警:", message);
  }
}

相关文档 ​

需要帮助? ​

如遇到问题:

  1. 查看本文档的错误码说明
  2. 查看 GitHub Issues
  3. 联系商务经理获取技术支持

基于飞书知识库同步生成,内容以飞书源文档为准