swaggernestjsschemaopenapidto

Modifying the DTO name appearing in OpenAPI (Swagger) schemas in NestJS


I am facing a problem where my DTO types are named one thing, but I want them to appear with a different name in the OpenAPI doc page. For example, I have a UserDto class that I use in my controller, but wanted it to appear as simply "User" in the schemas section (and everywhere else this applies). Is that possible? Is there any decorator I can use? I know I can simply modify the class name, but there is already a different user class used elsewhere. I have searched everywhere with no avail.

enter image description here

BTW, I am using typescript and nestjs. Every help will be appreciated, thanks!


Solution

  • Out of the box, Nest.js doesn't yet offer a ready-made solution. There is an open pull request (as mentioned earlier) https://github.com/nestjs/swagger/pull/983, but when it will be merged is unknown. You can change the DTO name in schemas using one of the following approaches:

    1. Add a static name property to your DTO.
      class UserDto {
        static name = 'User';  // <- here
    
        @ApiProperty()
        firstName: string;
    
        // ...
      }
    

    But in strict mode, TypeScript will show an error like: Static property 'name' conflicts with built-in property 'Function.name' of constructor function 'UserDto'.

    1. Write a decorator with an interface as suggested in the pull request and use it until the desired functionality appears in Nest.js. The decorator adds the name property with the needed value to the wrapper class for the DTO.
      type Constructor<T = object> = new(...args: any[]) => T;
      type Wrapper<T = object> = { new(): (T & any), prototype: T };
      type DecoratorOptions = { name: string };
      type ApiSchemaDecorator = <T extends Constructor>(options: DecoratorOptions) => (constructor: T) => Wrapper<T>;
    
      const ApiSchema: ApiSchemaDecorator = ({ name }) => {
        return (constructor) => {
          const wrapper = class extends constructor { };
          Object.defineProperty(wrapper, 'name', {
            value: name,
            writable: false,
          });
          return wrapper;
        }
      }
    

    Use as suggested in the proposal:

      @ApiSchema({ name: 'User' }) // <- here
      class UserDto {
        @ApiProperty()
        firstName: string;
    
        // ...
      }
    

    And don't forget that in TypeScript 5 the decorator API will change to something close to the implementation in JavaScript 😉