You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Swagger与Controller中使用不同的请求体Schema?

问题描述

我有一个创建新用户的Controller,请求体CreateUser包含可选字段locationName。我通过CreateUserLocationPipe管道将请求体中未定义的locationName转为null。运行时locationName绝不会是undefined,Swagger中也显示该字段为可选,但在代码中访问createUserInput.locationName时,TypeScript仍提示该值可能为undefined。请问如何为Controller代码和Swagger分别设置不同的类型?

User控制器代码:

@Post("/users")
async createUser(
  @Body(CreateUserLocationPipe) createUserInput: CreateUser
): Promise<User> {
  return await this.usersService.create(createUserInput);
}

CreateUser类:

export class CreateUser {
  @ApiProperty({ description: "用户邮箱" })
  email: string;

  @ApiProperty({ description: "用户所在地" })
  locationName: string | undefined | null;
}

CreateUserLocationPipe管道:

@Injectable()
export class CreateUserLocationPipe {
  transform(value: string | null | undefined): string | null {
    if (value.locationName === undefined) {
      value.locationName = null;
    }
  }
}

解决方案

核心思路是拆分Swagger请求类型和Controller处理后类型,让前者保留undefined以支持Swagger的可选字段展示,后者移除undefined让TypeScript正确识别运行时类型。

步骤1:拆分类型定义

保留CreateUser作为Swagger的请求输入类型,同时定义一个处理后的类型,确保locationName仅为string | null:

// 用于Swagger的请求输入类型,显式标记字段可选
export class CreateUser {
  @ApiProperty({ description: "用户邮箱" })
  email: string;

  @ApiProperty({ description: "用户所在地", required: false })
  locationName?: string | null;
}

// 处理后的类型,移除undefined,确保运行时类型准确
export type ProcessedCreateUser = Omit<CreateUser, 'locationName'> & {
  locationName: string | null;
};

步骤2:修复管道的类型与逻辑

修正管道的输入输出类型,确保它能正确转换CreateUser为ProcessedCreateUser,同时补全返回逻辑:

@Injectable()
export class CreateUserLocationPipe implements PipeTransform<CreateUser, ProcessedCreateUser> {
  transform(value: CreateUser): ProcessedCreateUser {
    if (value.locationName === undefined) {
      value.locationName = null;
    }
    return value as ProcessedCreateUser;
  }
}

步骤3:更新Controller的类型声明

在Controller中指定处理后的类型,让TypeScript识别createUserInput的实际运行时类型:

@Post("/users")
async createUser(
  @Body(CreateUserLocationPipe) createUserInput: ProcessedCreateUser
): Promise<User> {
  // 此时访问createUserInput.locationName,TypeScript不会再提示可能为undefined
  return await this.usersService.create(createUserInput);
}

补充说明

  • Swagger会基于CreateUser类生成文档,@ApiProperty({ required: false })确保字段显示为可选;
  • 管道处理后,createUserInput的类型是ProcessedCreateUser,TypeScript能准确判断locationName只能是string或null;
  • 原管道代码的参数类型错误,已修正为接收CreateUser对象,而非string | null | undefined。

内容的提问来源于stack exchange,提问作者Eranga Heshan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 15:13:16