# API Doc Template

一份可以照着写的接口文档。

# How to copy

<div id="bkmrk-%E5%A6%82%E4%BD%95%E5%A4%8D%E5%88%B6%E4%BD%BF%E7%94%A8-%E8%BF%99%E6%98%AF%E4%BB%80%E4%B9%88-%E6%9C%AC%E4%B9%A6%E6%98%AF%E9%85%B7%E5%8F%AF%E4%B8%8A%E7%BC%96%E5%86%99"># 如何复制使用

## 这是什么

本书是酷可上编写「产品 HTTP API 文档」的通用模板：一端点一页，章按资源分，样式用甲·浅底方章（`.cb-api-*`）。系统平台 API 仍在 [/api/docs](https://docs.cocobook.com/api/docs)，请勿把产品接口写进那个地址。

## 最快开写

- 新建一书（或复制本书，若站点开放复制）。
- 建概述页：粘贴「开始使用」骨架（Base URL / 鉴权 / 错误 / 限流）。
- 按资源建章；每接口一页，源码模式粘贴端点骨架，改方法、路径、参数表与 curl/fetch。
- 类名表与禁止事项见站内 SPEC（或本书附件/链到内部文档）。
 

## 必须遵守

- 一端点一页；试调只保留 curl / fetch 文本。
- 不要嵌入 Scalar、Swagger、Redoc 或自建试调表单。
- 方法徽章用 `cb-api-method--get|post|put|patch|delete`，不要用系统 `/api/docs` 的彩色 `api-method`。
 

## 以后

OAS → 书页自动生成会对齐同一 HTML；编辑器「插入 API 块」为后续增强。当前以粘贴骨架为准。

## 参考

- 端点示例页：本章「获取小部件」
- 现网甲案 demo（可选）：[/books/cocobook-api-jia-pre/page/listusers-get-users](https://docs.cocobook.com/books/cocobook-api-jia-pre/page/listusers-get-users)
- 平台 API：[/api/docs](https://docs.cocobook.com/api/docs)（标注：BookStack 平台，非本模板）
 
</div>**插入端点**：详见 [插入端点块](https://docs.cocobook.com/books/api-doc-template/page/insert-endpoint-block)（含完整可复制骨架）。

# Insert endpoint block

# 插入端点块

P0 写法：在编辑器里用**源码 / HTML**模式粘贴约定骨架，再改文案。编辑器「插入 API 块」按钮是后续增强，当前不依赖。

## 步骤

1. 新建页（建议页名：`动词 · 路径`，一端点一页）。
2. 编辑器切到**源码**（或 HTML）模式。
3. 清空默认空段落，粘贴下方「完整骨架」。
4. 改：方法徽章类名、路径、`operationId`、参数表、curl / fetch、响应 JSON。
5. 保存后在阅读壳预览；对照示例页 [获取小部件](https://docs.cocobook.com/books/api-doc-template/page/get-widget)。

## 方法徽章类名

<table class="cb-api-table" id="bkmrk-%E6%96%B9%E6%B3%95%E7%B1%BB%E5%90%8D-getcb-api-metho"><thead><tr><th>方法</th><th>类名</th></tr></thead><tbody><tr><td>GET</td><td><code>cb&#45;api&#45;method cb&#45;api&#45;method&#45;&#45;get</code></td></tr><tr><td>POST</td><td><code>cb&#45;api&#45;method cb&#45;api&#45;method&#45;&#45;post</code></td></tr><tr><td>PUT</td><td><code>cb&#45;api&#45;method cb&#45;api&#45;method&#45;&#45;put</code></td></tr><tr><td>PATCH</td><td><code>cb&#45;api&#45;method cb&#45;api&#45;method&#45;&#45;patch</code></td></tr><tr><td>DELETE</td><td><code>cb&#45;api&#45;method cb&#45;api&#45;method&#45;&#45;delete</code></td></tr></tbody></table>

## 必填块顺序

1. 根包裹 `div.cb-api`（一页一个）
2. `h1` 操作名
3. `.cb-api-endpoint`（方法徽章 + path）
4. `.cb-api-meta`（可选但推荐）
5. 简述 `p`
6. 参数表 `table.cb-api-table`（有则写）
7. 请求示例：至少 curl，建议再给 fetch（可用 `details.cb-api-fold` 折叠）
8. 响应：状态码芯片 + JSON 示例

## 禁止

- 不要嵌 Scalar / Swagger / Redoc / 试调表单
- 不要一页堆多个端点
- 不要用系统 `/api/docs` 的 `api-method` 色块
- 不要把产品接口写进 [/api/docs](https://docs.cocobook.com/api/docs)

更完整的类名表见本书 [如何复制使用](https://docs.cocobook.com/books/api-doc-template/page/how-to-copy)；概述骨架见 [开始使用](https://docs.cocobook.com/books/api-doc-template/page/getting-started)。

## 完整骨架（复制用）

下面是与「获取小部件」同构的 HTML。粘贴后把示例字段换成你的接口即可。

<div class="cb-api-example" id="bkmrk-html-%E6%BA%90%E7%A0%81-%3C%21---%E9%85%B7%E5%8F%AF-api-"> <span class="cb-api-example__label">HTML 源码</span>

```
<!-- 酷可 API 端点页骨架 · 粘贴到 BookStack 页 HTML/源码模式 -->
<!-- 一端点一页 · 甲·浅底方章 · 仅 curl/fetch 静态示例 · 勿嵌试调器 -->
<!-- PRE 20261102apiFoldPre：Header open fold · 请求示例 collapsed fold -->
<div class="cb-api">
  <h1>获取小部件</h1>

  <div class="cb-api-endpoint">
    <span class="cb-api-method cb-api-method--get">GET</span>
    <code class="cb-api-path">/v1/widgets/<var>id</var></code>
  </div>

  <p class="cb-api-meta">operationId: <code>getWidget</code> · 分组: Widgets · 鉴权: Bearer Token</p>

  <p>按 ID 返回单个小部件。路径参数 <code class="cb-api-param">id</code> 为资源主键；响应体字段以本文示例为准（可替换为你的 OAS 示例）。</p>

  <h2>Path 参数</h2>
  <table class="cb-api-table">
    <thead>
      <tr><th>名称</th><th>位置</th><th>类型</th><th>必填</th><th>说明</th></tr>
    </thead>
    <tbody>
      <tr>
        <td><code>id</code></td>
        <td>path</td>
        <td><span class="cb-api-type">string</span></td>
        <td><span class="cb-api-required">必填</span></td>
        <td>小部件 ID</td>
      </tr>
    </tbody>
  </table>

  <details class="cb-api-fold" open>
    <summary>Header 参数</summary>
    <table class="cb-api-table">
      <thead>
        <tr><th>名称</th><th>位置</th><th>类型</th><th>必填</th><th>说明</th></tr>
      </thead>
      <tbody>
        <tr>
          <td><code>Authorization</code></td>
          <td>header</td>
          <td><span class="cb-api-type">string</span></td>
          <td><span class="cb-api-required">必填</span></td>
          <td><code>Bearer &lt;token&gt;</code></td>
        </tr>
      </tbody>
    </table>
  </details>

  <details class="cb-api-fold">
    <summary>请求示例</summary>
    <div class="cb-api-example">
      <span class="cb-api-example__label">curl（静态示例；本页无试调表单）</span>
      <pre><code>curl -sS 'https://api.example.com/v1/widgets/wdg_42'   -H 'Authorization: Bearer YOUR_TOKEN'   -H 'Accept: application/json'</code></pre>
    </div>
    <div class="cb-api-example">
      <span class="cb-api-example__label">fetch</span>
      <pre><code>fetch('https://api.example.com/v1/widgets/wdg_42', {
  headers: {
    'Authorization': 'Bearer YOUR_TOKEN',
    'Accept': 'application/json'
  }
}).then(r =&gt; r.json())</code></pre>
    </div>
  </details>

  <h2>响应</h2>
  <h3><span class="cb-api-status">200</span> 成功</h3>
  <div class="cb-api-example">
    <span class="cb-api-example__label">application/json</span>
    <pre><code>{
  "id": "wdg_42",
  "name": "Demo Widget",
  "status": "active",
  "updated_at": "2026-11-02T08:00:00Z"
}</code></pre>
  </div>

  <h3><span class="cb-api-status cb-api-status--err">404</span> 未找到</h3>
  <p>ID 不存在或不在当前鉴权范围。</p>
  <div class="cb-api-example">
    <pre><code>{
  "error": {
    "code": 404,
    "message": "Widget not found"
  }
}</code></pre>
  </div>
</div>

```

</div>

# Getting Started

<div class="cb-api" id="bkmrk-%E5%BC%80%E5%A7%8B%E4%BD%BF%E7%94%A8-%E6%9C%AC%E6%96%87%E6%A1%A3%E8%AF%B4%E6%98%8E%E5%A6%82%E4%BD%95%E8%B0%83%E7%94%A8%E6%9C%AC%E4%BA%A7%E5%93%81%E7%9A%84-h"># 开始使用

本文档说明如何调用本产品的 HTTP API。系统 BookStack 平台 API 请另见 [/api/docs](https://docs.cocobook.com/api/docs)（与本书无关）。

## Base URL

<div class="cb-api-base">所有路径均相对于下方根地址（请改成你的环境）。

<div class="cb-api-example"> <span class="cb-api-example__label">生产</span>

```
https://api.example.com
```

 </div><div class="cb-api-example"> <span class="cb-api-example__label">沙箱（可选）</span>

```
https://api.sandbox.example.com
```

 </div> </div>## 鉴权

<div class="cb-api-auth">在请求头携带访问令牌（按你的实际方案改文案）：

<div class="cb-api-example"> <span class="cb-api-example__label">Header</span>

```
Authorization: Bearer <token>
```

 </div><div class="cb-api-example"> <span class="cb-api-example__label">curl</span>

```
curl -sS 'https://api.example.com/v1/widgets/wdg_42' \
  -H 'Authorization: Bearer YOUR_TOKEN'
```

 </div> </div>## 请求格式

写操作请设置 `Content-Type: application/json`。各端点接受的字段见对应页的参数表。

## 错误处理

成功一般为 <span class="cb-api-status">200</span> / <span class="cb-api-status">201</span> / <span class="cb-api-status">204</span>。失败返回 4xx/5xx，正文建议统一为：

<div class="cb-api-example">

```
{
  "error": {
    "code": 401,
    "message": "Unauthorized"
  }
}
```

 </div><table class="cb-api-table"> <thead> <tr><th>HTTP</th><th>含义</th><th>说明</th></tr> </thead> <tbody> <tr> <td><span class="cb-api-status cb-api-status--err">400</span></td> <td>参数错误</td> <td>校验失败；见 message</td> </tr> <tr> <td><span class="cb-api-status cb-api-status--err">401</span></td> <td>未鉴权</td> <td>缺少或无效 Token</td> </tr> <tr> <td><span class="cb-api-status cb-api-status--err">403</span></td> <td>无权限</td> <td>Token 有效但无权访问资源</td> </tr> <tr> <td><span class="cb-api-status cb-api-status--err">404</span></td> <td>未找到</td> <td>资源不存在</td> </tr> <tr> <td><span class="cb-api-status cb-api-status--err">429</span></td> <td>限流</td> <td>见下方 Rate Limits</td> </tr> </tbody> </table>

## 限流

默认示例：每用户每分钟 180 次（按你的网关改）。触发时返回 <span class="cb-api-status cb-api-status--err">429</span>。

<div class="cb-api-example"> <span class="cb-api-example__label">建议客户端行为</span>

```
# 尊重 Retry-After（若下发）
# 退避重试；避免突发打满配额
```

 </div>## 本书约定

- 一端点一页；章 = 资源。
- 页内使用 `.cb-api-*` 类；方法徽章为甲·浅底方章。
- 试调仅提供 curl / fetch 静态示例，无在线调试器。
 
</div>

# Widgets

资源章示例 · Widgets

# List widgets

<div class="cb-api" id="bkmrk-%E5%88%97%E5%87%BA%E5%B0%8F%E9%83%A8%E4%BB%B6-get-%2Fv1%2Fwidget"># 列出小部件

<div class="cb-api-endpoint"> <span class="cb-api-method cb-api-method--get">GET</span> <code>&#47;v1&#47;widgets</code> </div>operationId: <code>listWidgets</code> · 分组: Widgets · 鉴权: Bearer Token

分页列出小部件。 本页为模板 stub，字段可替换。

 <details class="cb-api-fold"> <summary>请求示例</summary>

<div class="cb-api-example"> <span class="cb-api-example__label">curl</span>

```
curl -sS -X GET 'https://api.example.com/v1/widgets' \
  -H 'Authorization: Bearer YOUR_TOKEN' \
  -H 'Accept: application/json'
```

 </div> </details>## 响应

### <span class="cb-api-status">200</span>

<div class="cb-api-example"> <span class="cb-api-example__label">application/json</span>

```
{
  "id": "wdg_42",
  "name": "Demo Widget"
}
```

 </div></div>

# Get widget

<div class="cb-api" id="bkmrk-%E8%8E%B7%E5%8F%96%E5%B0%8F%E9%83%A8%E4%BB%B6-get-%2Fv1%2Fwidget"># 获取小部件

<div class="cb-api-endpoint"> <span class="cb-api-method cb-api-method--get">GET</span> <code>&#47;v1&#47;widgets&#47;&#60;var&#62;id&#60;&#47;var&#62;</code> </div>operationId: <code>getWidget</code> · 分组: Widgets · 鉴权: Bearer Token

按 ID 返回单个小部件。路径参数 `id` 为资源主键；响应体字段以本文示例为准（可替换为你的 OAS 示例）。

## Path 参数

<table class="cb-api-table"> <thead> <tr><th>名称</th><th>位置</th><th>类型</th><th>必填</th><th>说明</th></tr> </thead> <tbody> <tr> <td><code>id</code></td> <td>path</td> <td><span class="cb-api-type">string</span></td> <td><span class="cb-api-required">必填</span></td> <td>小部件 ID</td> </tr> </tbody> </table>

 <details class="cb-api-fold" open=""> <summary>Header 参数</summary>

<table class="cb-api-table"> <thead> <tr><th>名称</th><th>位置</th><th>类型</th><th>必填</th><th>说明</th></tr> </thead> <tbody> <tr> <td><code>Authorization</code></td> <td>header</td> <td><span class="cb-api-type">string</span></td> <td><span class="cb-api-required">必填</span></td> <td><code>Bearer &#60;token&#62;</code></td> </tr> </tbody> </table>

 </details> <details class="cb-api-fold"> <summary>请求示例</summary>

<div class="cb-api-example"> <span class="cb-api-example__label">curl（静态示例；本页无试调表单）</span>

```
curl -sS 'https://api.example.com/v1/widgets/wdg_42' \
  -H 'Authorization: Bearer YOUR_TOKEN' \
  -H 'Accept: application/json'
```

 </div><div class="cb-api-example"> <span class="cb-api-example__label">fetch</span>

```
fetch('https://api.example.com/v1/widgets/wdg_42', {
  headers: {
    'Authorization': 'Bearer YOUR_TOKEN',
    'Accept': 'application/json'
  }
}).then(r => r.json())
```

 </div> </details>## 响应

### <span class="cb-api-status">200</span> 成功

<div class="cb-api-example"> <span class="cb-api-example__label">application/json</span>

```
{
  "id": "wdg_42",
  "name": "Demo Widget",
  "status": "active",
  "updated_at": "2026-11-02T08:00:00Z"
}
```

 </div>### <span class="cb-api-status cb-api-status--err">404</span> 未找到

ID 不存在或不在当前鉴权范围。

<div class="cb-api-example">

```
{
  "error": {
    "code": 404,
    "message": "Widget not found"
  }
}
```

 </div></div>

# Create widget

<div class="cb-api" id="bkmrk-%E5%88%9B%E5%BB%BA%E5%B0%8F%E9%83%A8%E4%BB%B6-post-%2Fv1%2Fwidge"># 创建小部件

<div class="cb-api-endpoint"> <span class="cb-api-method cb-api-method--post">POST</span> <code>&#47;v1&#47;widgets</code> </div>operationId: <code>createWidget</code> · 分组: Widgets · 鉴权: Bearer Token

创建小部件；请求体为 JSON。 本页为模板 stub，字段可替换。

## Body 参数

<table class="cb-api-table"> <thead><tr><th>名称</th><th>位置</th><th>类型</th><th>必填</th><th>说明</th></tr></thead> <tbody> <tr><td><code>name</code></td><td>body</td><td><span class="cb-api-type">string</span></td><td><span class="cb-api-required">必填</span></td><td>显示名</td></tr> </tbody> </table>

 <details class="cb-api-fold"> <summary>请求示例</summary>

<div class="cb-api-example"> <span class="cb-api-example__label">curl</span>

```
curl -sS -X POST 'https://api.example.com/v1/widgets' \
  -H 'Authorization: Bearer YOUR_TOKEN' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{"name":"Demo"}'
```

 </div> </details>## 响应

### <span class="cb-api-status">201</span>

<div class="cb-api-example"> <span class="cb-api-example__label">application/json</span>

```
{
  "id": "wdg_42",
  "name": "Demo Widget"
}
```

 </div></div>

# Delete widget

<div class="cb-api" id="bkmrk-%E5%88%A0%E9%99%A4%E5%B0%8F%E9%83%A8%E4%BB%B6-delete-%2Fv1%2Fwid"># 删除小部件

<div class="cb-api-endpoint"> <span class="cb-api-method cb-api-method--delete">DELETE</span> <code>&#47;v1&#47;widgets&#47;&#60;var&#62;id&#60;&#47;var&#62;</code> </div>operationId: <code>deleteWidget</code> · 分组: Widgets · 鉴权: Bearer Token

按 ID 删除小部件。 本页为模板 stub，字段可替换。

## Path 参数

<table class="cb-api-table"> <thead><tr><th>名称</th><th>位置</th><th>类型</th><th>必填</th><th>说明</th></tr></thead> <tbody> <tr><td><code>id</code></td><td>path</td><td><span class="cb-api-type">string</span></td><td><span class="cb-api-required">必填</span></td><td>小部件 ID</td></tr> </tbody> </table>

 <details class="cb-api-fold"> <summary>请求示例</summary>

<div class="cb-api-example"> <span class="cb-api-example__label">curl</span>

```
curl -sS -X DELETE 'https://api.example.com/v1/widgets/wdg_42' \
  -H 'Authorization: Bearer YOUR_TOKEN' \
  -H 'Accept: application/json'
```

 </div> </details>## 响应

### <span class="cb-api-status">204</span>

<div class="cb-api-example"> <span class="cb-api-example__label">application/json</span>

```
(无正文)
```

 </div></div>