swagger
swagger copied to clipboard
Registering custom decorators
I have a custom decorator for pagination using query strings but I have not been able to get Swagger to pick them up
// pagination.decorator.ts
import {createRouteParamDecorator} from '@nestjs/common';
import config from 'config';
import {Request} from 'express';
import {PaginationOptions} from './pagination.model';
export const Pagination: Function = createRouteParamDecorator(
(_: string, req: Request): PaginationOptions => {
req.query.limit = (typeof req.query.limit === 'number') ?
req.query.limit :
parseInt(req.query.limit, 10) || config.pagination.size;
req.query.page = (typeof req.query.page === 'number') ?
req.query.page :
parseInt(req.query.page, 10) || 1;
if (req.query.limit > config.pagination.max) {
req.query.limit = config.pagination.max;
} else if (req.query.limit < config.pagination.min) {
req.query.limit = config.pagination.min;
}
const limit: number = req.query.limit;
const page: number = req.query.page;
return {
limit,
page
};
}
);
// pagination.model.ts
import {ApiModelPropertyOptional} from '@nestjs/swagger';
export class PaginationOptions {
@ApiModelPropertyOptional() public readonly limit: number;
@ApiModelPropertyOptional() public readonly page: number;
}
// documents.controller.ts
....
@Get()
@ApiResponse(swagger.NOCONTENT)
@ApiResponse(swaggerWithType(swagger.OK, Document))
public async httpGetAll (
@Pagination() pagination: PaginationOptions
): Promise<PaginateResult<Role>> {
return this.documentService.readAll(pagination);
}
....
Hi @mogusbi,
You have to use @ApiImplicitQuery()
in this case (https://docs.nestjs.com/recipes/swagger)
Is there no way to get this module to automatically pick this up like it does for the standard @Body()
, @Param()
decorators?
Feels a bit cumbersome having to include the @ApiImplicitQuery()
decorator on every method which makes use of my custom @ Pagination()
decorator
Is there no way to get this module to automatically pick this up like it does for the standard
@Body()
,@Param()
decorators?Feels a bit cumbersome having to include the
@ApiImplicitQuery()
decorator on every method which makes use of my custom@ Pagination()
decorator
For anyone who is still interested in this, after reading the source code, I finally found out a way to achive this by passing a second paramter (enhancers
) to createParamDecorator
:
import { ApiQuery } from '@nestjs/swagger';
export const Pagination = createParamDecorator(
(data: unknown, context: ExecutionContext): PaginationParams => {
const request = context.switchToHttp().getRequest();
// Whatever logic you want to parse params in request
return {
pageSize: parseInt(request.query.pageSize, 10) || DEFAULT_PAGE_SIZE,
page: parseInt(request.query.page, 10) || 1
};
},
[
(target: any, key: string) => {
// Here it is. Use the `@ApiQuery` decorator purely as a function to define the meta only once here.
ApiQuery({
name: 'page',
schema: { default: 1, type: 'number', minimum: 1 },
required: false
})(target, key, Object.getOwnPropertyDescriptor(target, key));
ApiQuery({
name: 'page_size',
schema: { default: DEFAULT_PAGE_SIZE, type: 'number', minimum: 1 },
required: false
})(target, key, Object.getOwnPropertyDescriptor(target, key));
}
]
)
Then use the decorator in your controller just like what you used to do, swagger will pick up the extra params that you defined inside the decorator.
@Get()
@UseGuards(AuthGuard)
@Roles(...adminGroup)
@ApiQuery({ name: 'id', type: String })
@ApiQuery({ name: 'org', type: String })
async find(
@AuthorizedUser() user: IDTokenClaims,
@Pagination() pagination: PaginationParams
@Query('id') id: string,
@Query('org') organization: string
) {
// Use your customer decorator
console.log(pagination.page)
// Use handler-specific query param
console.log(id)
}