Skip to content

WebAPI vs OpenAPI

The Lovrabet data platform ships two complete API stacks: WebAPI and OpenAPI. Each has its strengths and fits different scenarios. This guide compares the two so you can pick the right one.

Core differences at a glance

DimensionWebAPI (Cookie mode)OpenAPI (Token/AccessKey mode)
AuthenticationBrowser Cookies (user session)HMAC-SHA256 signature (Token/AccessKey)
EnvironmentsBrowser onlyNode.js server + browser
Use casesSigned-in users reading private dataServer integrations, third-party systems, public data access
API path format/api/{appCode}/{datasetCode}/{method}/openapi/data/{method}
Request bodyFlat parameters: { currentPage, pageSize }Wrapped: { appCode, datasetCode, paramMap }
Auth headersNoneX-Token, X-Time-Stamp, etc. required
Security modelRelies on the Lovrabet login sessionIndependent signature verification + token expiry
Data permissionsBased on the user's permissionsBased on the app's authorized scope
CORSRequires credentials: 'include'Standard CORS

How they map to industry patterns

WebAPI - like a "session API"

WebAPI resembles the session-based APIs of traditional web apps. You'll find the same pattern in:

  • SaaS in-app APIs - the internal APIs behind the web apps of Salesforce, Notion, and friends
  • Embedded integrations - iframes inside a host app, sharing its login session
  • Single-page apps (SPA) - React/Vue apps calling their own backend

Characteristics:

  • Tightly coupled to the user's login state
  • No keys or signatures to manage
  • Permissions inherit the user's role
  • Built for user-level actions

OpenAPI - like a "RESTful API"

OpenAPI follows the industry-standard API-key-based authentication model, similar to:

  • AWS API - HMAC signing with an Access Key + Secret Key
  • Stripe API - API key authentication
  • GitHub API - Personal Access Tokens
  • Twilio API - Account SID + Auth Token

Characteristics:

  • Standalone authentication, independent of user sessions
  • Supports server-to-server (S2S) calls
  • Built for system integration and automation
  • Built for app-level actions

Detailed comparison

1. Authentication

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

// ✅ 无需提供任何认证信息
const client = createClient({
  appCode: "your-app-code",
  models: {
    users: { tableName: "users", datasetCode: "ds-001" },
  },
});

// 自动使用浏览器 Cookie,请求会包含 credentials: 'include'
const users = await client.models.users.filter();

Pros:

  • Zero configuration, no keys to manage
  • Inherits user permissions automatically
  • Great for fast iteration

Cons:

  • Browser-only
  • Must run on a Lovrabet domain or with CORS configured
  • No server-side or third-party use

OpenAPI - Token/AccessKey authentication

Mode 1: AccessKey on the server

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

const client = createClient({
  appCode: "your-app-code",
  accessKey: process.env.LOVRABET_ACCESS_KEY, // ⚠️ 只能在服务端使用
  models: {
    users: { tableName: "users", datasetCode: "ds-001" },
  },
});

// SDK 自动生成签名: HMAC-SHA256(accessKey + timestamp + appCode + datasetCode)
const users = await client.models.users.filter();

Mode 2: pre-generated token in the browser

TypeScript
// 服务端生成 Token
import { generateOpenApiToken } from "@lovrabet/sdk";

const { token, timestamp, expiresAt } = await generateOpenApiToken({
  appCode: "your-app-code",
  datasetCode: "ds-001",
  accessKey: process.env.LOVRABET_ACCESS_KEY,
});

// 浏览器使用 Token
const client = createClient({
  appCode: "your-app-code",
  token: token,
  timestamp: timestamp,
  models: {
    users: { tableName: "users", datasetCode: "ds-001" },
  },
});

Pros:

  • Works on the server and in the browser
  • Standalone authentication, no user login involved
  • Built for integration and automation
  • Finer-grained permission control

Cons:

  • The AccessKey must be stored securely
  • Tokens expire and need refreshing
  • The browser side needs an extra token endpoint

2. API paths

WebAPI path structure

Plain
/api/{appCode}/{datasetCode}/{method}

Examples:

Plain
POST /api/app-c2dd52a2/0fefba76fe29440194841f4825df53ff/getList
POST /api/app-c2dd52a2/0fefba76fe29440194841f4825df53ff/getOne
POST /api/app-c2dd52a2/0fefba76fe29440194841f4825df53ff/create

Characteristics:

  • RESTful style; the path carries the resource identifiers
  • Method names use camelCase (getList, getOne)
  • appCode and datasetCode live in the path

OpenAPI path structure

Plain
/openapi/data/{method}        # Data operations
/openapi/dataset/{method}     # Dataset metadata

Examples:

Plain
POST /openapi/data/get-list       # List records
POST /openapi/data/get-one        # Get a single record
POST /openapi/data/create         # Create a record

Characteristics:

  • One unified API endpoint
  • Method names use kebab-case (get-list, get-one)
  • appCode and datasetCode travel in the request body and headers

3. Request body structure

WebAPI request body

TypeScript
// getList 请求
POST /api/app-c2dd52a2/ds-001/getList
Content-Type: application/json

{
  "currentPage": 1,
  "pageSize": 20,
  "status": "active",
  "ytSortList": [
    { "gmt_create": "desc" }
  ]
}

Characteristics:

  • Business parameters are passed flat — no envelope
  • A flat, simple structure

OpenAPI request body

TypeScript
// getList 请求
POST /openapi/data/get-list
Content-Type: application/json
X-Time-Stamp: 1758903130713
X-App-Code: app-c2dd52a2
X-Dataset-Code: 0fefba76fe29440194841f4825df53ff
X-Token: jdqqGtzecF2I6FIW...

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

Characteristics:

  • Wrapped in an { appCode, datasetCode, paramMap } structure
  • Business parameters go inside paramMap
  • Credentials travel in both the headers and the body

The SDK hides the difference

With the SDK, none of this matters to you. It picks WebAPI or OpenAPI from your configuration, and the calling code is identical:

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

Choosing by scenario

Scenario 1: Custom pages on Lovrabet (micro-frontend integration)

The scenario:

You've built a business system on the Lovrabet platform (CRM, ERP, project management, etc.). The core features already cover your needs, but you want custom pages for specific business scenarios, integrated seamlessly into the main Lovrabet app.

Typical needs:

  • A sales-funnel analytics dashboard inside your Lovrabet order management system
  • A Gantt-timeline interactive view for your Lovrabet project management system
  • A data-import wizard that simplifies bulk imports
  • A custom dashboard showing company-specific KPIs

Recommended:WebAPI (Cookie mode) + icestark micro-frontend

The Lovrabet CLI scaffolds a micro-frontend sub-app in one shot, wiring up icestark, the SDK, and WebAPI authentication:

Bash
# 安装 CLI
npm install -g @lovrabet/cli

# 创建项目
lovrabet create my-custom-page

# 配置并拉取 SDK
lovrabet config set app <你的应用代>
lovrabet api pull

TIP

Full tutorial For the complete scaffolding and development workflow, see the Lovrabet CLI quick start.

Once scaffolding is done, use the SDK in your project:

TypeScript
// 从 CLI 自动生成的 API 文件中导入
import { lovrabetClient } from "@/api/client";

export default function Dashboard() {
  const [orders, setOrders] = useState([]);

  useEffect(() => {
    // 自动继承 Lovrabet 主应用登录态
    lovrabetClient.models.orders
      .filter(
        { status: "in_progress" },
        [{ gmt_create: "desc" }] // 使用 sortList 参数排序
      )
      .then((res) => setOrders(res.tableData));
  }, []);

  return <SalesFunnelChart data={orders} />;
}

Option 2: Integrate icestark manually (advanced)

If you need more flexible configuration, integrate icestark by hand.

TIP

Complete example We provide a full icestark sub-app sample project with complete configuration and best practices: 👉 sub-app-react-demo

Core code:

TypeScript
// 子应用入口 - src/index.tsx
import ReactDOM from "react-dom";
import { isInIcestark, setLibraryName } from "@ice/stark-app";
import { createClient } from "@lovrabet/sdk";
import App from "./App";

// 初始化 SDK(自动继承 Lovrabet 登录态)
const client = createClient({
  appCode: "your-app-code",
  models: {
    orders: { tableName: "orders", datasetCode: "ds-001" },
  },
});

// icestark 挂载生命周期
export function mount(props) {
  ReactDOM.render(<App sdkClient={client} {...props} />, props.container);
}

// icestark 卸载生命周期
export function unmount(props) {
  ReactDOM.unmountComponentAtNode(props.container);
}

// 设置库名称(需要与 webpack 配置的 output.library 保持一致)
setLibraryName("lovrabetSubApp");

// 独立运行时支持(开发调试)
if (!isInIcestark()) {
  ReactDOM.render(
    <App sdkClient={client} />,
    document.getElementById("ice-container")
  );
}

Lovrabet main-app configuration:

When the sub-app is ready, add a page configuration on the Lovrabet platform to integrate it with the main app.

Configuration steps:

  1. Add a source-code page on the Lovrabet platform Sign in to Lovrabet, open your app, and choose "Add page" → "Source-code page", then fill in the following: add a source-code page
  2. Configure the routing configure routing

Configuration fields:

FieldDescriptionExample
Route pathWhere the sub-app is reachable inside the main app/sales-funnel
Micro-app unique IDThe icestark appName; must match the sub-app's setLibraryName()salesFunnelApp
basenameBase path for the sub-app's routing (optional)Leave blank, or set a route prefix
Asset loading methodChoose import (for ES modules)ES Module import is recommended
Asset listURLs of the sub-app's built JS and CSS fileshttps://your-domain.com/dist/main.js
https://your-domain.com/dist/main.css

Sample configuration:

Plain
Route path: /sales-funnel
Micro-app unique ID: salesFunnelApp
Asset loading method: import (for ES modules)
Asset list:
  https://your-domain.com/dist/sales-funnel/main.js
  https://your-domain.com/dist/sales-funnel/main.css

Why it works well:

  • Seamless integration - the sub-app inherits the Lovrabet main app's session and permissions automatically
  • Zero-config auth - WebAPI Cookie mode, no AccessKey to manage
  • CLI support - one-command scaffolding, automatic configuration, fast development
  • Standalone development - icestark lets the sub-app run on its own

Related docs:


Scenario 2: Third-party mini programs and standalone apps

The scenario:

Build a standalone third-party app (WeChat mini program, WeCom app, DingTalk mini program, etc.) on the business APIs Lovrabet generates, with its own user system and permission control.

Typical needs:

  • A WeChat mini program for looking up customers, used by sales reps in the field
  • A WeCom app so employees can approve tickets on mobile
  • A DingTalk mini program showing real-time inventory
  • A standalone mobile app offered to partners

Recommended:OpenAPI (Token mode)

TypeScript
// 小程序端 - pages/index/index.js
import { createClient } from "@lovrabet/sdk";

Page({
  async onLoad() {
    // 步骤 1: 从后端获取 Token(后端使用 AccessKey 生成)
    const { token, timestamp } = await wx.request({
      url: "https://your-backend.com/api/get-lovrabet-token",
      method: "POST",
      data: { userId: this.getUserId() }, // 传递小程序用户ID
    });

    // 步骤 2: 使用 Token 创建客户端
    const client = createClient({
      appCode: "your-app-code",
      token: token,
      timestamp: timestamp,
      models: {
        customers: { tableName: "customers", datasetCode: "ds-001" },
      },
    });

    // 步骤 3: 查询客户数据
    const customers = await client.models.customers.filter({
      salesperson: this.getUserName(), // 根据销售人员过滤
      pageSize: 20,
    });

    this.setData({ customers });
  },
});

Backend token endpoint:

TypeScript
// 后端 API - /api/get-lovrabet-token
import { generateOpenApiToken } from "@lovrabet/sdk";

export async function POST(request) {
  const { userId } = await request.json();

  // 1. 验证小程序用户身份
  const user = await validateWechatUser(userId);
  if (!user) {
    return Response.json({ error: "未授权" }, { status: 401 });
  }

  // 2. 生成 Lovrabet OpenAPI Token
  const { token, timestamp, expiresAt } = await generateOpenApiToken({
    appCode: process.env.LOVRABET_APP_CODE,
    datasetCode: process.env.LOVRABET_DATASET_CODE,
    accessKey: process.env.LOVRABET_ACCESS_KEY,
  });

  // 3. 返回给小程序
  return Response.json({ token, timestamp, expiresAt });
}

Why it works well:

  • Independent user system - mini program users are fully separate from Lovrabet users
  • Your own permission control - the backend can mint tokens with different permissions based on each mini program user's role
  • Cross-platform - the same API serves WeChat, WeCom, DingTalk, and standalone apps
  • Secure and controllable - 10-minute tokens, plus finer-grained permission control in your backend

Fits: WeChat mini programs, WeCom, DingTalk, uniapp, React Native, Flutter, and more


Scenario 3: Server-side data integration (BI / data warehouse)

The scenario:

Sync business data from Lovrabet on a schedule into your enterprise data warehouse, BI system, or big-data platform for deep analysis and report generation.

Typical needs:

  • Sync Lovrabet order data into the warehouse every night
  • Stream customer records into your enterprise CRM in real time
  • Export data to Excel on a schedule for management
  • Connect to the enterprise data platform for unified data governance

Recommended:OpenAPI (AccessKey mode)

TypeScript
// cron-job.js - 定时任务脚本
import { createClient } from "@lovrabet/sdk";
import { syncToDataWarehouse } from "./utils";

const client = createClient({
  appCode: process.env.LOVRABET_APP_CODE,
  accessKey: process.env.LOVRABET_ACCESS_KEY,
  models: {
    orders: { tableName: "orders", datasetCode: "ds-001" },
    customers: { tableName: "customers", datasetCode: "ds-002" },
  },
});

// 每天凌晨 2 点执行
async function syncDailyData() {
  console.log("开始同步数据...");

  // 批量获取昨日订单
  const yesterday = new Date();
  yesterday.setDate(yesterday.getDate() - 1);

  let currentPage = 1;
  let totalSynced = 0;

  while (true) {
    const { tableData, paging } = await client.models.orders.filter({
      currentPage,
      pageSize: 100,
      create_date: yesterday.toISOString().split("T")[0],
    });

    // 同步到数据仓库
    await syncToDataWarehouse(tableData);
    totalSynced += tableData.length;

    if (currentPage * paging.pageSize >= paging.totalCount) break;
    currentPage++;
  }

  console.log(`同步完成,共 ${totalSynced} 条数据`);
}

Why it works well:

  • Runs server-side - AccessKey is used where it's safe, with no exposure risk
  • Batch-friendly - efficient syncing of large data volumes
  • Stable and reliable - no dependency on user logins; ideal for automated jobs
  • Flexible scheduling - run on a schedule, in real time, or on events, as needed

Scenario 4: Third-party system integration (ERP/OA/finance)

The scenario:

Your company already runs ERP, OA, or finance systems and needs two-way data flow with Lovrabet to connect business processes end to end.

Typical needs:

  • The ERP system reads Lovrabet customers and orders
  • The finance system pulls payment records from Lovrabet
  • OA approval flows validate against Lovrabet data
  • The e-commerce system syncs Lovrabet inventory

Recommended:OpenAPI (AccessKey mode)

Python
# Python ERP 系统集成示例
import requests
import hmac
import hashlib
import time

class LovrabetClient:
    def __init__(self, app_code, access_key):
        self.app_code = app_code
        self.access_key = access_key
        self.base_url = "https://runtime.lovrabet.com"

    def generate_token(self, dataset_code):
        timestamp = int(time.time() * 1000)
        params = f"accessKey={self.access_key}&appCode={self.app_code}&datasetCode={dataset_code}&timeStamp={timestamp}"
        token = hmac.new(
            b"lovrabet",
            params.encode('utf-8'),
            hashlib.sha256
        ).hexdigest()
        return token, timestamp

    def get_orders(self, dataset_code):
        token, timestamp = self.generate_token(dataset_code)

        response = requests.post(
            f"{self.base_url}/openapi/data/get-list",
            headers={
                "X-Time-Stamp": str(timestamp),
                "X-App-Code": self.app_code,
                "X-Dataset-Code": dataset_code,
                "X-Token": token,
                "Content-Type": "application/json"
            },
            json={
                "appCode": self.app_code,
                "datasetCode": dataset_code,
                "paramMap": {
                    "currentPage": 1,
                    "pageSize": 50,
                    "status": "confirmed"
                }
            }
        )

        return response.json()

# 在 ERP 系统中使用
client = LovrabetClient(
    app_code="your-app-code",
    access_key="your-access-key"
)

orders = client.get_orders("ds-001")
# 将订单数据同步到 ERP 系统
erp_system.sync_orders(orders['data']['tableData'])

Why it works well:

  • Language-agnostic - Python, Java, Go, PHP, any backend language
  • Standard protocol - HTTP + HMAC signing, understood industry-wide
  • Independent auth - no dependency on Lovrabet user logins
  • Enterprise-grade stability - ready for mission-critical integrations

Scenario 5: SSR apps (Next.js/Nuxt.js)

The scenario:

Build a server-rendered (SSR) web app on Lovrabet data, where both the server and the browser need data access.

Recommended:Hybrid (AccessKey on the server, Cookie or token in the browser)

TypeScript
// app/dashboard/page.tsx - Next.js Server Component
import { createClient } from "@lovrabet/sdk";

async function getDashboardData() {
  "use server";

  // 服务端使用 AccessKey
  const client = createClient({
    appCode: process.env.LOVRABET_APP_CODE,
    accessKey: process.env.LOVRABET_ACCESS_KEY,
    models: {
      stats: { tableName: "stats", datasetCode: "ds-001" },
    },
  });

  return await client.models.stats.filter();
}

export default async function DashboardPage() {
  const stats = await getDashboardData();

  // 服务端渲染,数据已在 HTML 中
  return <DashboardView initialData={stats} />;
}

// app/profile/page.tsx - Client Component
("use client");

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

export default function ProfilePage() {
  const [data, setData] = useState(null);

  useEffect(() => {
    // 浏览器端使用 Cookie(如果用户已登录 Lovrabet)
    const client = createClient({
      appCode: "your-app-code",
      models: {
        users: { tableName: "users", datasetCode: "ds-001" },
      },
    });

    client.models.users.getOne(userId).then(setData);
  }, []);

  return <ProfileView data={data} />;
}

Why it works well:

  • SEO-friendly - server-rendered content that search engines can crawl
  • Fast first paint - data is fetched on the server, so pages load faster
  • Flexible switching - fetch on the server or in the browser, per scenario

Security comparison

WebAPI security

Strengths:

  • ✅ Rides on Lovrabet's user authentication — mature and reliable
  • ✅ Permissions inherit the user automatically, so no over-reaching access
  • ✅ No keys in the frontend, so nothing to leak

Limitations:

  • ⚠️ Must run under a trusted domain or with correct CORS configured
  • ⚠️ Cookie-based, so your application must implement CSRF protection (CSRF tokens, SameSite Cookies, etc.)
  • ⚠️ Browser-only; no server-side use

Best practice:

TypeScript
// ✅ 正确:在浏览器端使用
const client = createClient({
  appCode: "your-app-code",
  models: { users: { tableName: "users", datasetCode: "ds-001" } },
});

// ❌ 错误:无法在 Node.js 使用
// 因为没有浏览器 Cookie

TIP

CSRF protection is your application's responsibility WebAPI authenticates with Cookies, so CSRF protection belongs to your application, not the API layer. Recommendations:

  1. CSRF tokens: add CSRF token validation to your forms
  2. SameSite Cookies: set the SameSite attribute on your Cookies
  3. Verify Referer/Origin: validate the request origin in your backend
  4. Framework CSRF middleware: Express csurf, Next.js built-in protection, etc. OpenAPI is immune to CSRF because it uses token-based authentication and never relies on Cookies sent automatically by the browser.

OpenAPI security

Strengths:

  • ✅ HMAC-SHA256 signing — an industry standard, proven and reliable
  • ✅ Token lifetime control (10 minutes) limits exposure
  • ✅ Standalone authentication, independent of user login state
  • ✅ Fine-grained permission control at the app level

Limitations:

  • ⚠️ A leaked AccessKey has serious consequences
  • ⚠️ Keys must be stored and transmitted securely
  • ⚠️ Tokens expire, so you need refresh logic

Best practice:

TypeScript
// ✅ 正确:服务端使用 AccessKey
// server.js (Node.js)
const client = createClient({
  appCode: process.env.APP_CODE,
  accessKey: process.env.LOVRABET_ACCESS_KEY, // 从环境变量读取
  models: { users: { tableName: "users", datasetCode: "ds-001" } },
});

// ✅ 正确:浏览器使用预生成 Token
// client.js (Browser)
const { token, timestamp } = await fetch("/api/token").then((r) => r.json());
const client = createClient({
  appCode: "your-app-code",
  token: token,
  timestamp: timestamp,
  models: { users: { tableName: "users", datasetCode: "ds-001" } },
});

// ❌ 错误:在浏览器代码中硬编码 AccessKey
const client = createClient({
  accessKey: "sk_live_xxxx", // 危险!会暴露在源代码中
});

Key management tips:

Bash
# .env 文件(不要提交到 Git)
LOVRABET_APP_CODE=app-c2dd52a2
LOVRABET_ACCESS_KEY=your-secret-access-key
LOVRABET_DATASET_CODE=0fefba76fe29440194841f4825df53ff

# .gitignore
.env
.env.local

Token management and refresh

Token lifetime

OpenAPI tokens are valid for 10 minutes; regenerate them once they expire.

Detecting expiry

TypeScript
import { isTokenExpiring, getTokenRemainingTime } from "@lovrabet/sdk";

// 检查是否即将过期(剩余时间 < 1分钟)
if (isTokenExpiring(timestamp)) {
  console.log("Token 即将过期,需要刷新");
}

// 获取剩余时间(毫秒)
const remaining = getTokenRemainingTime(timestamp);
console.log(`Token 剩余 ${remaining / 1000} 秒`);

Refresh strategies

Strategy 1: Refresh on a timer

TypeScript
let tokenData = await fetchToken();
let client = createClient({
  appCode: "your-app-code",
  token: tokenData.token,
  timestamp: tokenData.timestamp,
  models: { users: { tableName: "users", datasetCode: "ds-001" } },
});

// 每 8 分钟刷新一次(留 2 分钟缓冲)
setInterval(async () => {
  tokenData = await fetchToken();
  client.setToken(tokenData.token, tokenData.timestamp);
}, 8 * 60 * 1000);

Strategy 2: Lazy refresh (check before each request)

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

async function fetchData() {
  // 请求前检查 Token 是否即将过期
  if (isTokenExpiring(tokenData.timestamp)) {
    tokenData = await fetchToken();
    client.setToken(tokenData.token, tokenData.timestamp);
  }

  return await client.models.users.filter();
}

Strategy 3: Retry on error (recommended)

TypeScript
async function fetchDataWithRetry() {
  try {
    return await client.models.users.filter();
  } catch (error) {
    // 如果是 Token 过期错误(1003),刷新后重试
    if (error.statusCode === 1003) {
      tokenData = await fetchToken();
      client.setToken(tokenData.token, tokenData.timestamp);
      return await client.models.users.filter(); // 重试
    }
    throw error;
  }
}

Performance comparison

AspectWebAPIOpenAPI
LatencyLow (direct call)Low (direct call)
Signing overheadNoneHMAC-SHA256 (~1ms)
Token refreshNot neededEvery 10 minutes
ConcurrencyHighHigh
Server-side callsNot supportedSupported

Performance notes:

  1. WebAPI - ideal for high-frequency user interactions, with zero signing overhead
  2. OpenAPI - signing cost is negligible (<1ms), well suited to bulk data syncs

Migration guide

Migrating from WebAPI to OpenAPI

When: you need to call the API from a server

TypeScript
// Before: WebAPI (仅浏览器可用)
const client = createClient({
  appCode: "your-app-code",
  models: { users: { tableName: "users", datasetCode: "ds-001" } },
});

// After: OpenAPI (服务端可用)
const client = createClient({
  appCode: "your-app-code",
  accessKey: process.env.LOVRABET_ACCESS_KEY, // 添加 AccessKey
  models: { users: { tableName: "users", datasetCode: "ds-001" } },
});

// 调用方式完全相同,SDK 自动适配
const users = await client.models.users.filter();

Migrating from OpenAPI to WebAPI

When: a browser app for signed-in users where you want simpler authentication

TypeScript
// Before: OpenAPI (需要管理 Token)
const { token, timestamp } = await fetch("/api/token").then((r) => r.json());
const client = createClient({
  appCode: "your-app-code",
  token: token,
  timestamp: timestamp,
  models: { users: { tableName: "users", datasetCode: "ds-001" } },
});

// After: WebAPI (自动使用 Cookie)
const client = createClient({
  appCode: "your-app-code",
  // 不提供 accessKey 或 token,自动使用 Cookie
  models: { users: { tableName: "users", datasetCode: "ds-001" } },
});

// 调用方式完全相同
const users = await client.models.users.filter();

FAQ

Q1: How do I tell which mode I'm in?

TypeScript
const client = createClient({
  /* ... */
});

// 检查是否为 OpenAPI 模式
if (client.isOpenApiMode()) {
  console.log("当前使用 OpenAPI (Token/AccessKey)");
} else {
  console.log("当前使用 WebAPI (Cookie)");
}

Q2: Can one app use both modes?

Yes! Pick per environment:

TypeScript
// lib/sdk-client.ts
import { createClient } from "@lovrabet/sdk";

export function getClient() {
  // 服务端:使用 OpenAPI AccessKey
  if (typeof window === "undefined") {
    return createClient({
      appCode: process.env.APP_CODE,
      accessKey: process.env.LOVRABET_ACCESS_KEY,
      models: {
        /* ... */
      },
    });
  }

  // 浏览器端:使用 WebAPI Cookie
  return createClient({
    appCode: process.env.NEXT_PUBLIC_APP_CODE,
    models: {
      /* ... */
    },
  });
}

Q3: Does WebAPI support CORS?

Yes, but it needs configuration:

TypeScript
// 需要在 Lovrabet 平台配置允许的域名
// 或者将前端部署在 Lovrabet 同域下

Q4: Can the OpenAPI signing algorithm be customized?

No. The algorithm is fixed at HMAC-SHA256 and the secretKey is fixed at "lovrabet" — this guarantees security and compatibility.

Q5: What happens when a token expires?

TypeScript
try {
  const users = await client.models.users.filter();
} catch (error) {
  if (error.statusCode === 1003) {
    console.error("Token 已过期,请刷新 Token");
    // 刷新逻辑
  }
}

Quick selector

ScenarioRecommendedWhy
Custom Lovrabet micro-frontend pagesWebAPI (Cookie)Inherits the main-app session; zero config
Third-party mini programs / standalone appsOpenAPI (Token)Independent user system; your own permissions
Sync to BI / data warehouseOpenAPI (AccessKey)Server-side batch processing; stable and reliable
ERP/OA/finance integrationOpenAPI (AccessKey)Any language; enterprise-grade stability
Next.js SSR appsHybridAccessKey on the server, Cookie in the browser

Rules of thumb:

  • 🎯 Building inside Lovrabet → use WebAPI and enjoy the integrated experience
  • 🚀 Building standalone apps → use OpenAPI for independence and control
  • 🔄 Connecting systems → use OpenAPI (AccessKey) for a standard protocol
  • 🎨 Need flexibilitymix both modes

TIP

Where to read next

  • Micro-frontend integration? Scroll up to "Scenario 1: Custom pages on Lovrabet"
  • Mini program development? Scroll up to "Scenario 2: Third-party mini programs and standalone apps"
  • Data integration? Scroll up to Scenarios 3 and 4

Need help?

If something goes wrong:

  1. Browse GitHub Issues
  2. Contact your account manager for technical support

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