分页

如何用一个不透明游标走完任意一个集合,以及如何让一份副本保持最新。

这个 API 里的每一个列表都以同样的方式读取:你一页一页地走完一个 集合,收货记录也不例外。

GET /v1/restaurants/{restaurantId}/collections/{collection}/records
  ?limit=100
  &cursor=eyJpZCI6…
参数必填规则
limit否1 到 100。默认 50。
cursor否上一页的 nextCursor,一字不改地传回。

返回的是 { "data": [...], "nextCursor": string | null }。

没有时间区间

没有 from,也没有 to。一条记录会原地改变(一次更正、一条 tombstone),所以你 走完这个集合然后对账,而不是去要它的某一段窗口。要读一周的收货记录,就遍历 deliveries,留下 data.timestamp 落在那一周之内的记录。

排序

最早的改动在前:按 sequence 升序,也就是每条记录最近一次改动在变更流中的位置。 拿两个 sequence 来比较;不要拿一个去做算术。

逐页走完

nextCursor 在最后一页是 null,其他情况下是一个字符串。原封不动地把它传回去: 它是一个不透明的位置,不是一份供你解析的文档,它的内部结构会在不另行通知的情况下 改变。

async function* records({ apiKey, restaurantId, collection }) {
  const base = `https://api.backresto.com/v1/restaurants/${restaurantId}/collections/${collection}/records`;
  let cursor = null;

  do {
    const url = new URL(base);
    url.searchParams.set('limit', '100');
    if (cursor !== null) {
      url.searchParams.set('cursor', cursor);
    }

    const response = await fetch(url, {
      headers: { Authorization: `Bearer ${apiKey}` }
    });
    if (!response.ok) {
      throw new Error(`BackResto ${response.status}`);
    }

    const page = await response.json();
    yield* page.data;
    cursor = page.nextCursor;
  } while (cursor !== null);
}

一次遍历就是一份一致的快照。 第一页把这条变更流的位置钉住,之后的每一页都按 同一个位置作答。你在翻页期间写入的记录不会让页在你脚下移位。你会在下一次遍历时 看到它们。

游标绑定到餐厅、集合以及那个 limit。在一次遍历中途更改每页大小会返回 400: 选定一个 limit,整趟遍历都别改。

让一份副本保持最新

今天还没有 since 参数。一次刷新就是又一次遍历,然后你拿它和已经持有的数据对账:

  • 在一个集合内以 id 为键,当收到的 sequence 高于你存下的那个时就覆盖。
  • 认真对待 tombstone。 deleted: true 就是那条删除指令;照做是让你的副本不再 越跑越偏的唯一办法。
  • 预料到迟到的记录。 一台在营业期间离线的设备会在重新联网时上传,所以一条记录 可能在一次本应覆盖它 data.timestamp 的遍历之后才出现。用 capturedAt 做报表, 用 receivedAt 做同步。

一页空数据并不能证明什么都没发生。见 关于完整性的说明。

最后更新于 2026-09-29。