npm package: @fuibox/tsoa
Description: TSOA style API comment parser to OpenAPI 3.0
Author: Youzi
Latest version: 1.0.3

# OpenAPI TSOA

一个基于 TSOA 风格注释的 API 文档生成器，将代码注释自动转换为 OpenAPI 3.0 规范，可直接导入 Apifox、Swagger UI 等工具。

## ✨ 特性

- 🚀 **简洁注释**：使用简单的 TSOA 风格注释，无需复杂的配置
- 📝 **自动生成**：自动解析代码注释，生成标准的 OpenAPI 3.0 文档
- 🔧 **灵活配置**：支持通过 `.tsoa` 文件配置多环境服务器地址
- 🎯 **智能识别**：自动识别接口参数、响应、鉴权等信息
- 📦 **开箱即用**：支持命令行快速调用
- 🔄 **实时更新**：配合 nodemon 实现文档实时更新

## 📦 安装

### 本地项目使用

```bash
# 安装依赖
npm install glob --save-dev

# 本地链接（可选）
npm link
```

### 全局安装（如果发布到 npm）

```bash
npm install -g @fuibox/tsoa
```

## 🚀 快速开始

### 1. 创建配置文件（可选）

在项目根目录创建 `.tsoa` 文件：

```ini
# 服务器配置
dev=http://localhost:3000
test=https://test-api.example.com
prod=https://api.example.com

# 文档信息
title=My API Documentation
description=Complete API Documentation
version=1.0.0
```

### 2. 添加注释

#### 文件头注释（模块信息）

```javascript
/**
 * @tsoa
 * @module User
 * @baseRoute /user
 * @description 用户相关的所有接口
 * @version 1.0.0
 */

import express from "express";
const user_router = express.Router();
```

#### 接口注释

```javascript
/**
 * @tsoa
 * @summary 获取用户信息
 * @description 根据地址获取用户的详细信息，包括邀请码、余额等
 * @tags User
 * @route GET /user_info
 * @authorization true
 * @queryparam {string} address.required - 钱包地址（以0x开头）
 * @queryparam {string} inviteCode - 邀请码（可选）
 * @response 200 - 成功 - {"code": 0, "data": {"address": "0x123", "balance": 100}}
 * @response 400 - 参数错误 - {"code": 400, "message": "address is required"}
 * @response 401 - 未授权 - {"code": 401, "message": "Unauthorized"}
 */
user_router.get('/user_info', async (req, res) => {
    // 接口实现
});
```

### 3. 生成文档

```bash
# 使用默认路径 (endpoint/*.js)
tsoa

# 指定自定义路径
tsoa routes/*.js

# 指定单个文件
tsoa endpoint/user_app.js

# 扫描所有 JS 文件
tsoa "**/*.js"
```

### 4. 导入 Apifox

生成的文档位于 `docs/openapi.json`，在 Apifox 中：

1. 点击 **导入**
2. 选择 **OpenAPI/Swagger**
3. 上传 `docs/openapi.json`
4. 完成导入

## 📚 注释标签说明

### 文件级标签（模块信息）

| 标签 | 必填 | 说明 | 示例 |
|------|------|------|------|
| `@tsoa` | ✅ | 标识这是一个 API 文件 | `@tsoa` |
| `@module` | ✅ | 模块名称 | `@module User` |
| `@baseRoute` | ✅ | 基础路由路径 | `@baseRoute /user` |
| `@description` | ❌ | 模块描述 | `@description 用户相关接口` |
| `@version` | ❌ | 版本号 | `@version 1.0.0` |
| `@author` | ❌ | 作者 | `@author John Doe` |

### 接口级标签

| 标签 | 必填 | 说明 | 示例 |
|------|------|------|------|
| `@tsoa` | ✅ | 标识这是一个 API 接口 | `@tsoa` |
| `@summary` | ✅ | 接口简短描述 | `@summary 获取用户信息` |
| `@description` | ❌ | 接口详细说明 | `@description 详细的接口说明` |
| `@tags` | ❌ | 接口分组标签 | `@tags User` |
| `@route` | ✅ | HTTP 方法和路径 | `@route GET /user_info` |
| `@deprecated` | ❌ | 是否已弃用 | `@deprecated true` |
| `@deprecatedInfo` | ❌ | 弃用说明 | `@deprecatedInfo 请使用 v2 接口` |
| `@authorization` | ❌ | 是否需要鉴权 | `@authorization true` |
| `@queryparam` | ❌ | Query 参数 | `@queryparam {string} name.required - 描述` |
| `@bodyparam` | ❌ | Body 参数 | `@bodyparam {number} age.required - 年龄` |
| `@pathparam` | ❌ | Path 参数 | `@pathparam {string} id.required - 用户ID` |
| `@response` | ✅ | 响应定义 | `@response 200 - 成功 - {"code": 0}` |

### 参数格式

```javascript
@queryparam {type} name.required - description
@bodyparam {type} name - description (可选参数不加 .required)
@pathparam {type} name.required - description
```

**支持的类型**：`string`、`number`、`integer`、`boolean`、`array`、`object`

### 响应格式

```javascript
@response CODE - description - {json}
```

**示例**：

```javascript
@response 200 - 成功 - {"code": 0, "data": {"id": 1, "name": "John"}}
@response 400 - 参数错误 - {"code": 400, "message": "Invalid parameters"}
@response 401 - 未授权 - {"code": 401, "message": "Unauthorized"}
```

## 🔧 配置文件 (.tsoa)

### 基础配置

```ini
# 服务器配置
dev=http://localhost:3000
prod=https://api.example.com
```

### 完整配置

```ini
# 项目信息
title=My API Documentation
description=Complete API Documentation
version=2.0.0

# 服务器环境配置
dev=http://localhost:3000
test=https://test-api.example.com
staging=https://staging-api.example.com
prod=https://api.example.com
```

### 支持的配置项

**服务器配置**（支持任意环境名）：

- `dev` - 开发环境
- `test` - 测试环境
- `staging` - 预发布环境
- `prod` - 生产环境

**文档信息**：

- `title` - 文档标题
- `description` - 文档描述
- `version` - 版本号

## 📖 完整示例

### user_app.js

```javascript
/**
 * @tsoa
 * @module User
 * @baseRoute /user
 * @description 用户相关的所有接口
 * @version 1.0.0
 */

import express from "express";
const user_router = express.Router();

/**
 * @tsoa
 * @summary 用户登录
 * @description 通过钱包签名验证用户身份
 * @tags User
 * @route POST /login
 * @deprecated false
 * @authorization false
 * @bodyparam {string} address.required - 钱包地址
 * @bodyparam {string} signature.required - 签名
 * @response 200 - 登录成功 - {"code": 0, "data": {"token": "eyJhbGc..."}}
 * @response 400 - 参数错误 - {"code": 400, "message": "Invalid parameters"}
 * @response 401 - 签名验证失败 - {"code": 401, "message": "Invalid signature"}
 */
user_router.post('/login', async (req, res) => {
    // 实现逻辑
});

/**
 * @tsoa
 * @summary 获取用户信息
 * @description 获取用户的详细信息，包括余额、邀请码等
 * @tags User
 * @route GET /info
 * @deprecated false
 * @authorization true
 * @queryparam {string} address - 钱包地址（可选，未传则使用当前登录用户）
 * @response 200 - 成功 - {"code": 0, "data": {"address": "0x123", "balance": 100, "inviteCode": "ABC123"}}
 * @response 401 - 未授权 - {"code": 401, "message": "Unauthorized"}
 * @response 404 - 用户不存在 - {"code": 404, "message": "User not found"}
 */
user_router.get('/info', async (req, res) => {
    // 实现逻辑
});

/**
 * @tsoa
 * @summary 更新用户信息（旧版）
 * @description 此接口已弃用，请使用 PUT /v2/info
 * @tags User
 * @route PUT /update
 * @deprecated true
 * @deprecatedInfo 此接口将在 2025-12-31 下线，请迁移至 v2 版本
 * @authorization true
 * @bodyparam {string} nickname - 昵称
 * @bodyparam {string} avatar - 头像URL
 * @response 200 - 成功 - {"code": 0, "data": true}
 */
user_router.put('/update', async (req, res) => {
    // 实现逻辑
});

export default user_router;
```

### 生成的文档结构

```json
{
  "openapi": "3.0.0",
  "info": {
    "title": "My API Documentation",
    "description": "Complete API Documentation",
    "version": "1.0.0"
  },
  "servers": [
    {
      "url": "http://localhost:3000",
      "description": "开发环境"
    },
    {
      "url": "https://api.example.com",
      "description": "生产环境"
    }
  ],
  "tags": [
    {
      "name": "User",
      "description": "User 相关接口"
    }
  ],
  "paths": {
    "/user/login": {
      "post": {
        "summary": "用户登录",
        "description": "通过钱包签名验证用户身份",
        "tags": ["User"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "address": {
                    "type": "string",
                    "description": "钱包地址"
                  },
                  "signature": {
                    "type": "string",
                    "description": "签名"
                  }
                },
                "required": ["address", "signature"]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "登录成功",
            "content": {
              "application/json": {
                "schema": {
                  "code": 0,
                  "data": {
                    "token": "eyJhbGc..."
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}
```

## 📝 最佳实践

### 1. 统一响应格式

建议所有接口使用统一的响应格式：

```javascript
// 成功响应
{
  "code": 0,
  "data": { /* 实际数据 */ }
}

// 错误响应
{
  "code": 400,
  "message": "错误信息"
}
```

### 2. 业务错误码规范

```javascript
@response 200 - 成功 - {"code": 0, "data": {}}
@response 400 - 参数错误 - {"code": 400, "message": "Invalid parameters"}
@response 401 - 未授权 - {"code": 401, "message": "Unauthorized"}
@response 403 - 禁止访问 - {"code": 403, "message": "Forbidden"}
@response 404 - 资源不存在 - {"code": 404, "message": "Not found"}
@response 500 - 服务器错误 - {"code": 500, "message": "Internal server error"}
@response 701 - 业务错误1 - {"code": 701, "message": "Custom business error"}
@response 702 - 业务错误2 - {"code": 702, "message": "Another business error"}
```

### 3. 接口版本管理

```javascript
/**
 * @tsoa
 * @summary 获取用户信息（旧版）
 * @route GET /user/info
 * @deprecated true
 * @deprecatedInfo 请使用 GET /v2/user/info
 */

/**
 * @tsoa
 * @summary 获取用户信息（新版）
 * @route GET /v2/user/info
 * @deprecated false
 */
```

### 4. 文件组织建议

```
project/
├── endpoint/
│   ├── user_app.js      # 用户相关接口
│   ├── stake_app.js     # 质押相关接口
│   └── order_app.js     # 订单相关接口
├── scripts/
│   └── openapi-tsoa.js  # 文档生成脚本
├── docs/
│   └── openapi.json     # 生成的文档
├── .tsoa                # 配置文件
├── package.json
└── README.md
```

## 🤝 贡献

欢迎提交 Issue 和 Pull Request！

## 📄 License

MIT

## ❓ 常见问题

### Q: 为什么接口没有被解析？

A: 请检查：

1. 文件头注释是否包含 `@tsoa` 和 `@module`
2. 接口注释第一行是否包含 `@tsoa`
3. 接口注释是否包含必填标签：`@route`、`@summary`、`@response`

### Q: 如何添加自定义环境？

A: 在 `.tsoa` 文件中添加任意环境名：

```ini
dev=http://localhost:3000
test=https://test-api.example.com
custom=https://custom-api.example.com
```

### Q: 生成的文档在哪里？

A: 默认生成在 `docs/openapi.json`

### Q: 如何修改输出路径？

A: 修改脚本中的 `outputDir` 变量（计划支持配置）

### Q: 支持哪些 HTTP 方法？

A: 支持 `GET`、`POST`、`PUT`、`DELETE`、`PATCH` 等所有标准 HTTP 方法

## 📮 联系方式

如有问题或建议，请提交 [Issue](https://github.com/fuibox/tsoa/issues)