开发指南

本文档介绍如何使用 TypeSpec 开发和扩展 NexusBook API。

技术栈

技术 版本 用途
TypeSpec 1.6.0 API 定义语言
OpenAPI 3.0 API 规范标准
Redocly 2.12.0 API 文档生成

前置要求

  • Node.js 16+
  • Make

快速开始

安装依赖

# 安装 npm 依赖
make deps

# 或者手动安装
npm install

生成文档

# 生成 OpenAPI 规范
make openapi

# 构建 API 文档
make build-docs

# 构建完整文档站点
make docs

# 预览文档(浏览器访问 http://localhost:8091)
make serve

输出文件

文件 说明
dist/openapi/@typespec/openapi3/*.yaml OpenAPI 规范文件
docs/api/index.html Redoc 单页 API 文档
docs/ 完整文档站点(生成)
docs-src/ 文档源文件(Markdown)
dist/openapi/openapi.yaml 合并后的 OpenAPI 入口文件

项目命令

# 开发相关
make deps          # 安装依赖
make openapi       # 生成 OpenAPI 规范
make build-docs    # 构建 Redoc 文档
make serve-docs    # 预览 Redoc 文档(端口 8091)

# 文档站点
make docs          # 构建完整文档站点
make serve         # 启动文档服务器(端口 8091)
make clean-docs    # 清理生成的文档

# 清理
make clean         # 清理生成的文件

添加新模块

1. 创建模块目录

mkdir -p api/extensions/webhooks

2. 创建 TypeSpec 文件

// api/extensions/webhooks/models.tsp
import "@typespec/http";
import "../../shared/index.tsp";

namespace NexusBook.Extensions.Webhooks {
  model Webhook {
    id: string;
    url: string;
    events: string[];
  }
  
  @route("/webhooks")
  interface WebhooksApi {
    @get list(): ApiResponse<Webhook[]>;
    @post create(@body webhook: Webhook): ApiResponse<Webhook>;
  }
}

3. 创建模块入口

// api/extensions/webhooks/index.tsp
import "./models.tsp";

4. 在主入口引入

// api/main.tsp
import "./extensions/webhooks/index.tsp";

5. 重新生成

make openapi
make docs

修改现有模块

  1. 编辑对应的 .tsp 文件
  2. 运行 make openapi 重新生成 OpenAPI
  3. 运行 make docs 重新生成文档站点
  4. 运行 make serve 预览变更

编辑文档

文档结构

docs-src/              # 文档源文件(提交到 Git)
├── guides/           # 开发指南
├── references/       # 参考文档
├── styles/           # 样式文件
├── README.md         # 文档说明
└── CONTRIBUTING.md   # 贡献指南

docs/                 # 生成的文档(不提交到 Git)
├── guides/           # 生成的指南 HTML
├── references/       # 生成的参考 HTML
├── styles/           # 复制的样式
├── api/              # Redoc API 文档
└── index.html        # 文档主页

添加新文档

  1. 在 docs-src/guides/ 或 docs-src/references/ 创建 Markdown 文件
  2. 编辑 scripts/build-docs.js,添加文件到对应数组
  3. 运行 make docs 生成 HTML

示例:

// scripts/build-docs.js
const guides = [
  // ... 现有文档
  { file: 'my-new-guide', title: '新指南标题' }
];

文档注释规范

使用中英文双语注释

/**
 * 获取文档元数据
 *
 * Get document metadata
 *
 * 返回字段定义与显示配置,供渲染与校验使用。
 * Returns field definitions and display settings for rendering and validation.
 */
@get
@summary("获取文档元数据")
getMetadata(...): ApiResponse<Metadata>;

添加示例

/**
 * 创建数据行
 *
 * Create data row
 *
 * 示例(cURL):
 * ```bash
 * curl -X POST 'https://open.nexusbook.app/api/v1/doc/product/123/data?apply=true' \
 *   -H 'Authorization: Bearer TOKEN' \
 *   -H 'Content-Type: application/json' \
 *   -d '{"id":"row-1","values":[{"fieldId":"name","value":{"text":"新产品"}}]}'
 * ```
 */

测试 API

使用 curl

# 设置环境变量
export API_BASE="https://open.nexusbook.app/api/v1"
export TOKEN="your_access_token"

# 测试端点
curl -H "Authorization: Bearer $TOKEN" \
  "$API_BASE/doc/product/123/metadata"

使用 Postman

  1. 导入生成的 OpenAPI 文件
  2. 配置环境变量(base_url, token)
  3. 测试各个端点

调试技巧

查看生成的 OpenAPI

# 查看 API 规范
cat dist/openapi/@typespec/openapi3/openapi.NexusBook.Api.yaml

# 使用 yq 格式化查看
yq eval dist/openapi/@typespec/openapi3/openapi.NexusBook.Api.yaml

验证 TypeSpec 语法

npx tsp compile api/main.tsp --no-emit

查看编译错误

TypeSpec 编译器会提供详细的错误信息,包括:

  • 文件位置
  • 错误类型
  • 修复建议

常见问题

Q: 如何添加新的错误码?

在 api/shared/common.tsp 中的 ErrorCode 枚举添加:

enum ErrorCode {
  // ... 现有错误码
  NEW_ERROR_CODE,  // 新错误码
}

Q: 如何添加新的字段类型?

  1. 在 api/shared/constants.tsp 的 FieldType 枚举添加
  2. 在 api/shared/common.tsp 的 Value union 添加对应类型
  3. 重新生成 OpenAPI

Q: 如何修改响应格式?

修改 api/shared/common.tsp 中的 ApiResponse 模型,但建议保持向后兼容。

Q: 如何使用生成的 OpenAPI 规范?

生成的 OpenAPI 文件 (dist/openapi/openapi.yaml) 可以:

  1. 用于任意后端语言的代码生成

    • Python: openapi-generator
    • Java/Kotlin: openapi-generator
    • TypeScript/JavaScript: openapi-typescript-codegen
    • 其他语言:查看 OpenAPI Generator
  2. 导入到 API 测试工具

    • Postman
    • Insomnia
    • Swagger UI
  3. 生成客户端 SDK

例如使用 Python:

openapi-generator-cli generate -i dist/openapi/openapi.yaml -g python -o client-python

Q: 如何调试 TypeSpec 编译错误?

  1. 检查导入路径是否正确
  2. 确认所有引用的类型都已定义
  3. 使用 --trace 选项查看详细信息:
    npx tsp compile api/main.tsp --trace
    

Q: 如何优化 OpenAPI 文档生成?

  1. 添加详细的 @summary 和 @doc 注释
  2. 使用 @example 提供示例
  3. 为模型字段添加描述
  4. 使用 @deprecated 标记废弃的 API

Q: 文档站点样式丢失怎么办?

确保 docs-src/styles/main.css 存在,然后运行:

make docs

TypeSpec 最佳实践

1. 模块组织

  • 按功能划分模块(core, content, workflow)
  • 每个模块有独立的 index.tsp 入口
  • 相关的模型和接口放在一起

2. 命名规范

  • Model 名称: PascalCase(如 DataRow, Metadata)
  • Interface 名称: PascalCase + Api 后缀(如 DataApi, ViewsApi)
  • 字段名称: camelCase(如 fieldId, createdAt)
  • 枚举值: UPPER_SNAKE_CASE(如 DOC_NOT_FOUND)

3. 类型复用

// 定义可复用的类型
model PageRequest {
  page?: int32 = 1;
  pageSize?: int32 = 20;
}

// 在接口中使用
@get list(...PageRequest): ApiResponse<DataRow[]>;

4. 错误处理

所有接口统一返回 ApiResponse<T> 类型:

@get
getMetadata(): ApiResponse<Metadata>;

5. 版本控制

  • 在路径中包含版本号:/api/v1
  • 重大变更时增加版本号
  • 保持向后兼容性

6. 文档注释

/**
 * 中文说明
 * 
 * English description
 */
@summary("简短摘要")
@doc("详细说明")

扩展建议

添加新的文档类型

  1. 实现对应的 Provider 接口
  2. 注册到路由系统
  3. 无需修改 TypeSpec 定义

添加新的字段类型

  1. 在 FieldType 枚举添加新类型
  2. 在 Value union 添加对应的值类型
  3. 更新字段类型文档

添加新的视图类型

  1. 在 ViewType 枚举添加新类型
  2. 定义视图配置模型
  3. 实现前端渲染逻辑

添加新的事件类型

  1. 在 Webhook 事件枚举添加
  2. 定义事件载荷结构
  3. 实现事件触发逻辑

贡献指南

提交代码

  1. Fork 本仓库
  2. 创建特性分支 (git checkout -b feature/AmazingFeature)
  3. 提交变更 (git commit -m 'Add some AmazingFeature')
  4. 推送到分支 (git push origin feature/AmazingFeature)
  5. 开启 Pull Request

代码规范

  • 遵循现有的代码风格
  • 添加适当的注释(中英文)
  • 更新相关文档
  • 确保 TypeSpec 编译通过

提交信息规范

type(scope): subject

body

footer

类型:

  • feat: 新功能
  • fix: 修复 bug
  • docs: 文档更新
  • style: 代码格式
  • refactor: 重构
  • test: 测试
  • chore: 构建/工具

示例:

feat(api): 添加 Webhook 支持

- 添加 Webhook 管理接口
- 支持 20+ 种事件类型
- 实现 HMAC 签名验证

Closes #123

下一步