开发者

把一本书标记为读过,就是一次 API 操作。

用户在书架中把作品标记为“读过”,网站发送的就是下面这个请求。你的程序发送相同的请求,会得到相同的结果,也会经过相同的检查。

写入

逐行看一个写入请求

PUT /v1/works/{id}/reader-status
Authorization: Bearer …
Idempotency-Key: 7f3c2a9e-read
Content-Type: application/json

{
  "actingSubject":
    "https://rezics.com/id/…",
  "expectedVersion": 3,
  "status": "read",
  "finishedOn": "2026-10-19"
}
版本号、日期和幂等键仅作示意。
  • 路径指向一部作品

    {id}

    REZICS 中的每个实体都有一个以 https://rezics.com/id/ 开头的固定标识符,切换语言或站点后仍然相同。

  • 注明身份

    actingSubject

    一个账户可以代表自己,也可以代表组织。每次写入都要注明以哪个身份操作,服务器会在执行前检查该身份的权限。

  • 安全重试

    Idempotency-Key

    每次写入都带有幂等键。超时或断线后,用同一个键重试,不会重复写入。

  • 避免覆盖

    expectedVersion

    你读取的是第 3 版,写入时就注明第 3 版。如果期间有人先做了修改,本次写入不会覆盖对方的内容。

  • 错误会返回问题详情

    application/problem+json

    失败时,code 是固定代码,程序按它分支处理,无需比对消息文本。

重试

重试同一个请求,得到同一个结果。

使用同一个键再次发送相同内容,服务器会返回第一次的结果,版本仍是 4,replayed 变为 true。同一个键对应不同内容时,返回 409 reader_status_conflict;版本已不是 3 时,返回 409 stale_reader_status,需要重新读取后再写入。

  • 首次请求

    200
    {
      "status": "read",
      "version": 4,
      "replayed": false
    }
  • 重试

    200
    {
      "status": "read",
      "version": 4,
      "replayed": true
    }
  • 版本过期

    409
    {
      "status": 409,
      "code":
        "stale_reader_status"
    }

类型

API 和类型来自同一份定义

REZICS 网站使用 TypeScript 调用 API,请求和响应的类型直接取自服务器的路由声明。字段改名或新增错误代码时,调用端在编译时就会发现。TypeScript SDK 也由同一份定义生成,因此你拿到的类型和网站相同。

OpenAPI 3.1 文档也由同一份路由声明生成,注明每项操作的验证方式、请求格式和各状态码对应的响应。

main().v1
  .works({ id: uuid(work) })
  ['reader-status'].put({
    actingSubject,
    expectedVersion,
    status: 'read',
    ...dates,
  }, headers())
摘自 REZICS 网站的书架功能。

generated/openapi/main/public.json

读取

读取也有规则

  • nextCursor · snapshot

    长列表会附上下一页游标,方便逐页读到底。导出的书架数据还会附带快照;如果数据在中途发生变化,会明确说明,不会让你拼凑文件。

  • count.precision

    搜索结果总数会注明是精确值,还是“至少这么多”。

  • title.language · basis

    标题附有语言标签和书写方向,并说明这是你指定的语言、同一种文字的语言、其他文字的语言,还是备用语言。

  • 404 resource_unavailable

    你无权查看的资源会像不存在的资源一样响应,不会泄露它的存在。

用同一套 API,打造自己的工具。

让自己的程序读写作品、书架和社区数据。每次操作都遵循 REZICS 的身份与授权规则。