About NestJS
Use `applyDecorators`, `ApiExtraModels`, `getSchemaPath` to implement customize swagger decorator, introduce swagger cli plugin. How to use ESM in Nest.JS? 如何解决 @nestjs/swagger 出现 schema 被覆盖的问题?
NestJS 自定义 Swagger 装饰器
https://docs.nestjs.com/openapi/operations#advanced-generic-apiresponse
比如统一泛型返回类型
1type ApiResponse<T> = {
2 timestamp: string;
3
4 path: string;
5
6 pathViewCount: number;
7
8 data: T;
9}
但是 Swagger ApiResponse 并不能使用泛型,只能使用 Class。
可以使用自定义如下注解实现类似效果
1import type { Type } from '@nestjs/common';
2import { applyDecorators } from '@nestjs/common';
3import { ApiExtraModels, ApiOkResponse, ApiResponseProperty, getSchemaPath } from '@nestjs/swagger';
4import type { ReferenceObject } from '@nestjs/swagger/dist/interfaces/open-api-spec.interface';
5
6class ResponseInterceptorResult {
7 @ApiResponseProperty()
8 timestamp: string;
9
10 @ApiResponseProperty()
11 path: string;
12
13 @ApiResponseProperty()
14 pathViewCount: number;
15}
16
17export const ApiOkInterceptorResultResponse = <T extends Type>(options: {
18 model: T;
19 description?: string;
20 isArray?: boolean;
21}) => {
22 const { model, description, isArray } = options;
23 const ref: ReferenceObject = { $ref: getSchemaPath(model) };
24 return applyDecorators(
25 ApiExtraModels(ResponseInterceptorResult),
26 ApiExtraModels(model),
27 ApiOkResponse({
28 description,
29 schema: {
30 allOf: [
31 {
32 $ref: getSchemaPath(ResponseInterceptorResult),
33 },
34 {
35 properties: {
36 data: isArray ? { type: 'array', items: ref } : ref,
37 },
38 },
39 ],
40 },
41 }),
42 );
43};
Swagger Cli Plugin
关于 NestJS 不支持 ESM 的一个解决办法
如何解决 @nestjs/swagger 出现重名 class 导致 schema 被覆盖的问题?
比如有两个 User 重名,使用 extends 取别名修改 class name 来避免被覆盖。
1export class GithubUser extends User {
2 // ...
3}
关于allOf
、anyOf
和oneOf
关键字的示例
以下是一些更详细的关于allOf
、anyOf
和oneOf
关键字的示例。
-
allOf
示例:假设我们有一个基础用户模型(BaseUser),包含
id
和email
属性,另外还有一个名为AdminUser
的扩展模型,添加了role
属性。1components: 2 schemas: 3 BaseUser: 4 type: object 5 properties: 6 id: 7 type: integer 8 email: 9 type: string 10 AdminUser: 11 allOf: 12 - $ref: '#/components/schemas/BaseUser' 13 - type: object 14 properties: 15 role: 16 type: string
在这个示例中,
AdminUser
模型继承自BaseUser
模型,并添加了role
属性。使用allOf
关键字可以将BaseUser
的属性与AdminUser
的属性组合在一起。 -
anyOf
示例:假设我们有两个不同类型的用户模型:
InternalUser
和ExternalUser
,它们具有不同的属性。在某些场景下,我们可能需要一个API可以接受这两种类型的用户之一。1components: 2 schemas: 3 InternalUser: 4 type: object 5 properties: 6 id: 7 type: integer 8 username: 9 type: string 10 ExternalUser: 11 type: object 12 properties: 13 externalId: 14 type: integer 15 emailAddress: 16 type: string 17 MixedUser: 18 anyOf: 19 - $ref: '#/components/schemas/InternalUser' 20 - $ref: '#/components/schemas/ExternalUser'
在这个示例中,我们创建了一个名为
MixedUser
的模型,它可以是InternalUser
或ExternalUser
。使用anyOf
关键字表示该模型需要满足这两个模型之一的属性。 -
oneOf
示例:假设我们有两种不同类型的支付方式:信用卡(CreditCard)和支付宝(Alipay)。我们希望一个API接受的支付方式是这两种中的一种,但不能同时为两者。
1components: 2 schemas: 3 CreditCard: 4 type: object 5 properties: 6 cardNumber: 7 type: string 8 expiryDate: 9 type: string 10 cvv: 11 type: integer 12 Alipay: 13 type: object 14 properties: 15 account: 16 type: string 17 PaymentMethod: 18 oneOf: 19 - $ref: '#/components/schemas/CreditCard' 20 - $ref: '#/components/schemas/Alipay'
在这个示例中,我们创建了一个名为
PaymentMethod
的模型,它可以是CreditCard
或Alipay
,但不能同时为两者。使用oneOf
关键字表示该模型需要满足这两个模型中恰好一个的属性。
nest.js 搭配 jest 单元测试时 exit gracefully
使用 onModuleDestroy 来优雅关闭连接或者后台任务