Cell - OpenAPI 组件
将 @celljs/openapi 添加到依赖中,以文档化你的 @celljs/mvc 控制器的 API:应用程序在 /openapi.json 提供 OpenAPI 3.0 文档,在 /api-docs 提供 Swagger UI。文档是从路由本身构建的(路径、@Param / @Query / @Header / @Cookie / @Body、TypeScript 参数和返回类型),因此始终与代码保持同步;@Api* 装饰器添加类型无法表达的内容。示例:examples/openapi-app。
ts
import { Body, Controller, Get, Param, Post, Query } from '@celljs/mvc/lib/node';
import { ApiOperation, ApiProperty, ApiPropertyOptional, ApiResponse, ApiTags } from '@celljs/openapi';
import { IsInt, IsOptional, IsString, Min } from 'class-validator';
export class CreatePet {
@IsString() // class-validator 装饰器成为了 schema:类型、必需、枚举、长度、范围...
@ApiProperty({ example: 'Tom' }) // ...而 @ApiProperty 添加描述、示例或数组的类型
name: string;
@IsInt() @Min(0) @IsOptional()
age?: number;
}
export class Pet extends CreatePet {
@ApiProperty()
id: number;
}
@Controller('pets')
@ApiTags('Pets')
export class PetController {
@Get()
@ApiResponse({ type: [Pet] }) // 异步方法和数组需要类型:TypeScript 只会发出 Promise / Array
list(@Query() query: PetQuery): Promise<Pet[]> { ... }
@Get(':id')
@ApiOperation({ summary: 'Find a pet' })
@ApiResponse({ status: 404, description: 'No such pet' })
get(@Param('id') id: number): Pet { ... } // 返回类型是 200 响应
@Post()
create(@Body() pet: CreatePet): Pet { ... } // body 的类是请求 schema
}文档中包含的内容:
- 路径:控制器的每个路由,
:id表示为{id};可选部分(/users(/:id))生成一个有它的路径和一个没有它的路径。带有 RegExp 路径的路由被排除。 - 参数:
@Param('id')、@Query('q')、@Header('x-name')、@Cookie('name')和参数的类型;@Query() query: PetQuery为类的每个属性给出一个查询参数。方法中缺少的路径参数作为字符串添加。 - Body:
@Body() pet: CreatePet作为application/jsonbody;命名的@Body('name')参数作为对象的属性。 - 响应:
@ApiResponse的那些(在类上对所有方法,或在方法上);如果没有 2xx 的响应,则200带有返回类型。内容类型遵循视图:默认为 JSON,@Text()为text/plain,@Html()为text/html。 - Schema:每个类成为
components.schemas的一个条目,由$ref引用。其属性是那些带有 class-validator 装饰器的属性(从 class-validator 的元数据中读取,当它被安装时,例如使用 @celljs/validation;它不是此包的依赖)或带有@ApiProperty的属性。属性是必需的,除非它有@IsOptional()或@ApiPropertyOptional()。 - 标签:
@ApiTags,否则是控制器名称(去掉Controller)。
| 装饰器 | 在 | 目的 |
|---|---|---|
@ApiTags(...tags) | 类、方法 | 对操作进行分组 |
@ApiOperation({ summary, description, operationId, deprecated }) | 方法 | 描述操作;operationId 默认为 <Class>_<method> |
@ApiResponse({ status, description, type, schema, contentType }) | 类、方法 | 一个响应;按状态重复;type: [Pet] 表示列表 |
@ApiProperty(options) / @ApiPropertyOptional(options) | 属性 | 请求或响应类的属性;type、enum(列表或 TypeScript 枚举)、description、example、format 和任何其他 schema 字段 |
@ApiParam / @ApiQuery / @ApiHeader({ name, ... }) | 方法 | 描述参数,或记录方法从请求本身读取的参数 |
@ApiSecurity(name, scopes?) / @ApiBearerAuth() | 类、方法 | 需要安全方案;当 components.securitySchemes 中没有时,bearer 被声明为 @ApiBearerAuth() |
@ApiExclude() | 类、方法 | 将其从文档中排除 |
配置
yaml
openapi:
enabled: true # false:既不提供文档也不提供 UI
url: /openapi.json # 在 server.path 下
ui:
enabled: true
url: /api-docs
cdn: https://cdn.jsdelivr.net/npm/swagger-ui-dist@5 # 页面从中加载 Swagger UI 的位置
document: # 合并到生成的文档中
openapi: 3.0.3
info:
title: Pet Store
version: 1.0.0
servers:
- url: https://api.example.com
components:
securitySchemes:
apiKey: { type: apiKey, in: header, name: X-API-Key }文档和页面响应任何控制器未应答的 GET 请求,因此应用程序的具有相同路径的路由赢得,其他请求无需付出任何代价。除非 @celljs/security 保护它们,否则是公开的;要在生产中隐藏它们,在生产配置中设置 enabled: false(cell.production.yml)。
要写文档到文件而不启动服务器(用于 API 客户端、代码生成器或审核),从 @celljs/cli 的 createTestApp() 中获取它,如示例的 scripts/export-openapi.ts 所做。
OpenApiDocumentProvider(@celljs/openapi/lib/node)在代码中提供文档;重新绑定它以改变构建方式。