4

I'm trying to correctly define OpenAPI spec for the purposes of generating api client from that spec. I've encoutered a problem where we have a complex query object with nested objects and arrays of objects for get a GET route.

Lets take these classes as an example.

class Person {
  @ApiProperty()
  name!: string
  @ApiProperty()
  location!: string
}

class CompanyDto {
  @ApiProperty()
  name!: string

  @ApiProperty({
    type: [Person],
  })
  employees!: Person[]
}

And a get request with @Query decorator.

  @Get('test')
  async testing(@Query() dto: CompanyDto): Promise<void> {
    // ...
  }

What I'm getting is.

    {
      get: {
        operationId: 'testing',
        parameters: [
          {
            name: 'name',
            required: true,
            in: 'query',
            schema: {
              type: 'string',
            },
          },
          {
            name: 'name',
            in: 'query',
            required: true,
            schema: {
              type: 'string',
            },
          },
          {
            name: 'location',
            in: 'query',
            required: true,
            schema: {
              type: 'string',
            },
          },
        ],
        responses: {
          '200': {
            description: '',
          },
        },
        tags: ['booking'],
      },
    }

I've also tries to define Query params by adding @ApiQuery decorator and it almost works.

  @ApiQuery({
    style: 'deepObject',
    type: CompanyDto,
  })

--

{
  get: {
    operationId: 'testing',
    parameters: [
      {
        name: 'name',
        required: true,
        in: 'query',
        schema: {
          type: 'string',
        },
      },
      {
        name: 'name',
        in: 'query',
        required: true,
        schema: {
          type: 'string',
        },
      },
      {
        name: 'location',
        in: 'query',
        required: true,
        schema: {
          type: 'string',
        },
      },
      {
        name: 'name',
        in: 'query',
        required: true,
        schema: {
          type: 'string',
        },
      },
      {
        name: 'employees',
        in: 'query',
        required: true,
        schema: {
          type: 'array',
          items: {
            $ref: '#/components/schemas/Person',
          },
        },
      },
    ],
    responses: {
      '200': {
        description: '',
      },
    },
    tags: ['booking'],
  },
}

However now I'm getting duplicate query definitions mashed in to one. Is there a way to prevent or overwrite @Query definition? Or just a better way to define complex @Query in general?

Laurynas
  • 41
  • 1
  • 5
  • OpenAPI [does not support](https://stackoverflow.com/q/67745944/113116) nested objects in query parameters. Send nested objects in the POST request body instead. – Helen Feb 07 '22 at 09:35
  • Thanks, I'll use POST for requests with nested objects. However I would still like to use GET for non-nested objects. Is there any way to overwrite or disable spec generation from @Query decorator to prevent duplicate parameter definition? – Laurynas Feb 07 '22 at 10:47
  • I'm not famliar with NestJs. Maybe someone else here knows. – Helen Feb 07 '22 at 11:49

1 Answers1

0

Ended up creating a custom decorator to extract query without generating OpenAPI Spec.

export const SilentQuery = createParamDecorator(
  (data: string | undefined, ctx: ExecutionContext) => {
    const request = ctx.switchToHttp().getRequest()
    if (data) {
      return request.query[data]
    } else {
      return request.query
    }
  },
)

So now you can use @ApiQuery with deepObject style.

Also if your're using ValidationPipes with class-validator for example. Make sure to set validateCustomDecorators to true

@SilentQuery(new ValidationPipe({ validateCustomDecorators: true }))
Laurynas
  • 41
  • 1
  • 5