Search code examples
nestjsopenapinestjs-swaggerexpress-openapi-validator

NestJs/Swagger: How to add `additionalProperties: false` on an existing DTO class


Hello I am new to Nestjs and trying to implement additionalProperties: false on a DTO class that already has properties on it. I see that the additionalProperties key can be added inside @ApiProperty({ schema: ... { additionalProperties : false} }) but I want to add it like this:

class SomeResponseDto {

  @ApiResponseProperty()
  text: string;

  @ApiResponseProperty()
  id: string;

  // maybe a new Decorator like this?
  @ApiAdditionalProperties(false)

}

...so that only text and id is allowed in the SomeResponseDto. I want to avoid having to define every class as a schema object inside the controllers.

I should note that I'm using express-openapi-validator with nestjs/swagger, and do not want to use the class-validator/class-transformer plugins, so that I can validate responses as well as requests by using just nestjs/swagger decorators.

I have also tried this:

@ApiResponse({
    status: 200,
    description: 'success',
    schema: {
      oneOf: [
        {
          $ref: getSchemaPath(SomeResponseDto),
          // additionalProperties: false,  <-- this gets ignored
        },
      ],
      // additionalProperties: false, <-- this throws OpenApi invalid response errors
    },

Is there any easy way to add additionalProperties: false on an existing DTO class?


Solution

  • Here is a workaround: Post this code inside the bootstrap() method of the application

      const schemas = document?.components?.schemas;
      Object.keys(schemas).forEach((item) => {
        if (schemas[item]['properties']?.allowAdditional) {
          schemas[item]['additionalProperties'] = true;
        } else {
          schemas[item]['additionalProperties'] = false;
        }
      });
    

    This code above will set additionalProperties to false by default.

    If for some reason you have a DTO class that you want to allow additionalProperties: true, then inside your DTO Class, add the following decorator and property:

    export class SomeResponseDTO {
      @ApiPropertyOptional()
      allowAdditional?: boolean;
    
      @ApiResponseProperty()
      text: string;
    
      @ApiResponseProperty()
      id: string;
    }
    

    This is a simple solution for true/false case, but can be modified as needed to handle other use cases.

    I hope this helps someone!