docupress-api
v0.2.1
Published
轻量优雅的 Node.js API 文档生成工具
Maintainers
Readme
docupress-api
一个轻量、优雅的 Node.js API 文档生成工具。使用装饰器声明接口信息,自动生成美观的 API 文档页面。
✨ 特性
- 零侵入 — 纯装饰器声明,不依赖任何框架,Koa/Express/NestJS/Midway 通用
- 运行时收集 — 无需扫描文件,装饰器执行时自动注册
- 开箱即用 — 内置精美文档模板,支持暗色主题
- 在线调试 — 内置 API 调试功能,支持参数编辑和请求发送
- 灵活配置 — 全局 headers、响应包装器、多环境切换、鉴权配置
- TypeScript 友好 — 完整的类型定义
📦 安装
npm install docupress-api
# or
pnpm add docupress-api
# or
yarn add docupress-api⚙️ 配置
在 tsconfig.json 中启用装饰器:
{
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}🚀 快速开始
1. 全局配置
import { defineConfig, HttpHeader, AuthIn } from "docupress-api";
defineConfig({
title: "用户服务 API",
description: "用户管理相关接口",
version: "1.0.0",
servers: [
{ name: "开发环境", url: "http://localhost:3000" },
{ name: "生产环境", url: "https://api.example.com" },
],
headers: [
{
name: HttpHeader.Authorization,
description: "Bearer Token",
required: true,
},
],
author: {
name: "张三",
email: "[email protected]",
phone: "13800138000",
},
});2. 定义 DTO
import { ApiModel, ApiSchema, DataType } from "docupress-api";
@ApiModel({ description: "用户信息" })
class UserDto {
@ApiSchema({ type: DataType.INTEGER, description: "用户ID", example: "1" })
id: number;
@ApiSchema({
type: DataType.STRING,
description: "用户名",
required: true,
minLength: 2,
maxLength: 20,
})
name: string;
@ApiSchema({
type: DataType.STRING,
description: "邮箱",
format: "email",
example: "[email protected]",
})
email: string;
}3. 定义接口
import { ApiOperation, ApiTag, ApiExample, HttpMethod } from "docupress-api";
@ApiTag({ name: "用户管理", description: "用户增删改查" })
class UserController {
@ApiOperation({
method: HttpMethod.GET,
path: "/users",
summary: "获取用户列表",
query: UserQueryDto,
response: UserDto,
})
@ApiExample({
name: "成功响应",
response: [{ id: 1, name: "张三", email: "[email protected]" }],
})
getUsers() {}
@ApiOperation({
method: HttpMethod.POST,
path: "/users",
summary: "创建用户",
body: CreateUserDto,
response: UserDto,
})
createUser() {}
}4. 渲染文档
import { render, getApiDocs } from "docupress-api";
// 方式一:直接渲染 HTML
const html = render();
// 方式二:获取结构化数据(可自行渲染或转换格式)
const data = getApiDocs();5. 集成到 Web 框架
Koa:
import Koa from "koa";
import { render, getApiDocs } from "docupress-api";
const app = new Koa();
app.use(async (ctx) => {
if (ctx.path === "/api-docs") {
ctx.type = "html";
ctx.body = render();
} else if (ctx.path === "/api-docs/json") {
ctx.type = "json";
ctx.body = getApiDocs();
}
});
app.listen(3000);Express:
import express from "express";
import { render, getApiDocs } from "docupress-api";
const app = express();
app.get("/api-docs", (req, res) => {
res.type("html").send(render());
});
app.get("/api-docs/json", (req, res) => {
res.json(getApiDocs());
});
app.listen(3000);📖 装饰器详解
@ApiOperation
定义接口信息,用于方法。
| 参数 | 类型 | 必填 | 说明 |
| ------------- | -------------- | ---- | -------------------------- |
| method | HttpMethod | 否 | 请求方式,默认 GET |
| path | string | 否 | 路由路径 |
| summary | string | 否 | 简要描述 |
| description | string | 否 | 详细描述 |
| deprecated | boolean | 否 | 是否废弃,默认 false |
| params | Function | 否 | 路径参数 DTO 类 |
| query | Function | 否 | 查询参数 DTO 类 |
| body | Function | 否 | 请求体 DTO 类 |
| response | Function | 否 | 响应体 DTO 类 |
| rawHeaders | boolean | 否 | 跳过全局请求头,默认 false |
| rawResponse | boolean | 否 | 跳过响应包装器,默认 false |
| author | AuthorConfig | 否 | 接口联系人 |
HttpMethod 枚举值: GET POST PUT DELETE PATCH HEAD OPTIONS TRACE CONNECT
@ApiOperation({
method: HttpMethod.POST,
path: '/users/:id',
summary: '更新用户',
params: UserParamsDto,
body: UpdateUserDto,
response: UserDto,
author: { name: '李四', email: '[email protected]' }
})
updateUser() {}@ApiSchema
定义字段类型和约束,用于属性。
| 参数 | 类型 | 必填 | 说明 |
| --------------- | ---------- | ---- | ------------------------------ |
| type | DataType | 否 | 数据类型,默认 STRING |
| description | string | 否 | 字段描述 |
| example | string | 否 | 示例值 |
| required | boolean | 否 | 是否必填,默认 false |
| ref | string | 否 | 引用类型(复杂对象) |
| allowedValues | string[] | 否 | 允许的值(枚举) |
| minLength | number | 否 | 最小长度(字符串/数组) |
| maxLength | number | 否 | 最大长度(字符串/数组) |
| minimum | string | 否 | 最小值(数字) |
| maximum | string | 否 | 最大值(数字) |
| format | string | 否 | 格式(如 date-time, email 等) |
DataType 枚举值: STRING NUMBER INTEGER BOOLEAN ARRAY OBJECT FILE
@ApiSchema({
type: DataType.INTEGER,
description: '年龄',
required: true,
minimum: '0',
maximum: '150',
example: '25'
})
age: number;@ApiModel
标记 DTO 类,用于类。
| 参数 | 类型 | 必填 | 说明 |
| ------------- | -------- | ---- | -------- |
| description | string | 否 | 模型描述 |
@ApiModel({ description: "用户创建参数" })
class CreateUserDto {
// ...
}@ApiTag
接口分组,可用于类或方法。
| 参数 | 类型 | 必填 | 说明 |
| ------------- | -------------- | ---- | ---------- |
| name | string | 是 | 标签名称 |
| description | string | 否 | 标签描述 |
| author | AuthorConfig | 否 | 分组联系人 |
@ApiTag({
name: "用户管理",
description: "用户增删改查接口",
author: { name: "张三", email: "[email protected]" },
})
class UserController {}@ApiHeader
定义请求头,用于方法,可多次使用。
| 参数 | 类型 | 必填 | 说明 |
| ------------- | ------------------------ | ---- | ---------- |
| name | HttpHeader | string | 是 | 请求头名称 |
| description | string | 否 | 描述 |
| required | boolean | 否 | 是否必填 |
| example | string | 否 | 示例值 |
HttpHeader 枚举值: Authorization ContentType Accept AcceptLanguage CacheControl UserAgent XRequestId XForwardedFor XRealIp Origin Referer Cookie SetCookie
@ApiHeader({ name: HttpHeader.Authorization, description: 'Token', required: true })
@ApiHeader({ name: 'X-Custom-Header', description: '自定义头' })
@ApiOperation({ ... })
getUsers() {}@ApiExample
定义请求/响应示例,用于方法,可多次使用。
| 参数 | 类型 | 必填 | 说明 |
| ------------- | -------- | ---- | -------------------- |
| name | string | 否 | 示例名称 |
| description | string | 否 | 示例描述 |
| request | any | 否 | 请求示例 |
| response | any | 否 | 响应示例 |
| status | number | 否 | 响应状态码,默认 200 |
@ApiExample({
name: '成功响应',
request: { name: '张三', email: '[email protected]' },
response: { id: 1, name: '张三' },
status: 201
})
@ApiExample({
name: '参数错误',
response: { code: 400, message: '参数错误' },
status: 400
})
@ApiOperation({ ... })
createUser() {}🔧 高级配置
全局配置项
defineConfig({
// 基础信息
title: "API 文档",
description: "接口描述",
version: "1.0.0",
// 环境配置
servers: [
{ name: "开发环境", url: "http://localhost:3000", description: "本地开发" },
{ name: "生产环境", url: "https://api.example.com" },
],
// 全局请求头
headers: [
{ name: HttpHeader.Authorization, description: "Token", required: true },
],
// 响应包装器
wrapper: {
model: ResponseWrapper,
dataField: "data",
},
// 鉴权配置
auth: {
in: AuthIn.HEADER,
field: "Authorization",
prefix: "Bearer ",
description: "登录后自动获取",
extractFrom: {
path: "/login",
field: "data.token",
},
},
// 文档作者
author: {
name: "张三",
email: "[email protected]",
phone: "13800138000",
url: "https://example.com",
},
// 许可证
license: {
name: "MIT",
url: "https://opensource.org/licenses/MIT",
},
});响应包装器
统一响应格式,避免重复定义:
@ApiModel()
class ResponseWrapper {
@ApiSchema({ type: DataType.INTEGER, example: "0" })
code: number;
@ApiSchema({ type: DataType.STRING, example: "success" })
message: string;
@ApiSchema()
data: any;
}
defineConfig({
wrapper: {
model: ResponseWrapper,
dataField: "data",
},
});鉴权配置
支持自动从登录接口提取 token 并填充到所有接口:
defineConfig({
auth: {
in: AuthIn.HEADER, // 字段位置:HEADER / QUERY / BODY
field: "Authorization", // 字段名
prefix: "Bearer ", // 前缀(可在页面修改)
description: "登录后自动获取",
extractFrom: {
path: "/login", // 登录接口路径
field: "data.token", // 响应中 token 的路径
},
},
});AuthIn 枚举值: HEADER QUERY BODY
跳过全局配置
某些接口不需要全局 headers 或响应包装:
@ApiOperation({
method: HttpMethod.GET,
path: '/health',
rawHeaders: true, // 跳过全局 headers
rawResponse: true // 跳过响应包装
})
healthCheck() {}作者配置
支持三个级别的联系人配置:
// 1. 全局级别
defineConfig({
author: { name: "张三", email: "[email protected]" },
});
// 2. 分组级别
@ApiTag({
name: '用户管理',
author: { name: '李四', email: '[email protected]' }
})
class UserController {}
// 3. 接口级别
@ApiOperation({
method: HttpMethod.DELETE,
path: '/users/:id',
author: { name: '王五', email: '[email protected]' }
})
deleteUser() {}📄 License
MIT © 陈佳宝
