Is it possible to dynamically set the parameters of a decorator?

2k Views Asked by At

I have several endpoints that allow pagination and return an object containing the paginated items as well as the max number of pages possible. For example, if I have 41 documents and returning 5 documents per page, it would look like:

{
  items: [...],
  maxPages: 9
}

I have also made a custom decorator in order to group ApiOkResponse and ApiQuery together like so:

export function Pagination() {
  return applyDecorators(
      ApiQuery({ name: page, type: Number }),
      ApiOkResponse({description: 'items and metadata', type: PaginationObjectDTO})
    );
}

export class PaginationObjectDTO{
  @ApiProperty({isArray: true})
  items
  @ApiProperty({type: Number})
  maxPages
}

I was wondering if it would be possible to dynamically set the type in @ApiProperty in order to reuse the same DTO with different object types like below. I tried creating a constructor in the DTO but it would return an error. Is it possible or should I just create different DTOs for each?

   @Get('dogs/:page')
   @Pagination(Dog)
   async getDogs(page)

   @Get('cats/:page')
   @Pagination(Cat)
   async getCats(page)

This is the closest I've gotten to it so far:

export class PaginationObjectDTO{
  @ApiPropertyOptional({isArray: true })
  items;

  @ApiPropertyOptional({type: Number})
  maxPages

  constructor(type){
    Object.assign(this.items, {type: type})
  }
}

export function Pagination(type?) {
  let typeDef = new PaginationObjectDTO(type)
  return applyDecorators(
      ApiQuery({ type: Number, name: page}),
      ApiOkResponse({description: 'Documents and metadata', type:typeDef })
    );
}

However assigning typeDef to type gives "type is not assignable" error

1

There are 1 best solutions below

0
On

You can follow this: for example :

decorator:  @ApiPagination(Cat) || @ApiPagination(Dog)

decorator file:

import { applyDecorators, Type } from '@nestjs/common';
import { ApiExtraModels, ApiOkResponse, getSchemaPath } from '@nestjs/swagger';
    export const ApiPagination = <TModel extends Type<any>>(model: TModel) => {
      return applyDecorators(
        ApiExtraModels(model),
        ApiOkResponse({
          description: '',
          content: {
            'application-json': {
              schema: {
                properties: {
                  items: {
                    type: 'array',
                    items: {
                      $ref: getSchemaPath(model),
                    },
                  },
                  pagination: {
                    type: 'object',
                    properties: {
                      count: { type: 'number' },
                      pageSize: { type: 'number' },
                      page: { type: 'number' },
                    },
                  },
                },
              },
            },
          },
        }),
      );
    };