Nest.js自定义Swagger返回体

开发后台服务时总会定义一个通用的返回结构,可以通过NestJS自带的自定义装饰器方法”applyDecorators”,将这个过程简化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
import { applyDecorators, Type } from '@nestjs/common';
import { ApiOkResponse, getSchemaPath, ApiProperty, ApiExtraModels } from '@nestjs/swagger';
import { IsOptional } from 'class-validator';
import { BaseHttpResponsePageOptionDto } from './comm.dto';
import { EResultCode } from './enum';

export class BaseDocHttpResponseDto<TData> {
@ApiProperty({ description: '业务是否成功' })
ok: boolean;
@ApiProperty({ description: '0请求正常、1接口错误、2无权限、3服务器错误、4token过期' })
code: EResultCode;

@IsOptional()
@ApiProperty({ description: '服务器消息' })
message?: string;
@ApiProperty({ description: '服务器时间戳' })
ts: number;

@IsOptional()
@ApiProperty({ description: '返回值' })
data?: TData;
}

export class BaseDocHttpResponsePageDto<T = any> extends BaseDocHttpResponseDto<T> {
@IsOptional()
@ApiProperty({ description: '分页数据' })
page: BaseHttpResponsePageOptionDto;
}

export const BaseDocApiResponse = <TModel extends Type<any>>(opt: { type: TModel; isArray?: boolean; isPage?: boolean }) => {
const resWrap = opt.isPage ? { $ref: getSchemaPath(BaseDocHttpResponsePageDto) } : { $ref: getSchemaPath(BaseDocHttpResponseDto) };

const res = (() => {
if (opt.isArray || opt.isPage) {
return {
properties: {
data: {
type: 'array',
items: { $ref: getSchemaPath(opt.type) },
},
},
};
}

// 返回基本数据类型
const _type =
((opt.type as any) === String && 'string') ||
((opt.type as any) === Number && 'number') ||
((opt.type as any) === Boolean && 'boolean') ||
'';
if (_type)
return {
properties: {
data: {
type: _type,
},
},
};

return {
properties: {
data: {
$ref: getSchemaPath(opt.type),
},
},
};
})();

return applyDecorators(
ApiExtraModels(opt.type),
ApiOkResponse({
status: 200,
schema: {
allOf: [resWrap, res],
},
})
);
};

使用示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
class UserVo {
@ApiProperty({
description: 'id',
})
id: string;
@ApiProperty({
description: '用户名称',
})
name: string;
}


@Controller('base')
export class BaseController {
@Get('get')
// 返回值为字符串时,传入String
@BaseDocApiResponse({
type: String,
})
async getVariable() {
// ...
}

@Post('login')
// 将反回体传入type
@BaseDocApiResponse({
type: UserVo,
})
async login() {
// ...
}

@Post('list')
@ApiOperation({ summary: '用户查询' })
@BaseDocApiResponse({
type: UserVo,
// 返回为数组
isArray: true,
// 是否为分页
isPage: true,
})
async list() {
// ...
}
}