Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Registering custom decorators #32

Open
mogusbi opened this issue Jan 13, 2018 · 3 comments
Open

Registering custom decorators #32

mogusbi opened this issue Jan 13, 2018 · 3 comments

Comments

@mogusbi
Copy link

mogusbi commented Jan 13, 2018

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);
  }
....
@kamilmysliwiec
Copy link
Member

Hi @mogusbi,
You have to use @ApiImplicitQuery() in this case (https://docs.nestjs.com/recipes/swagger)

@mogusbi
Copy link
Author

mogusbi commented Jan 14, 2018

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

@ziliwesley
Copy link

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)
  }

davidmehren added a commit to hedgedoc/hedgedoc that referenced this issue Jan 10, 2021
As explained in nestjs/swagger#32 (comment), it's possible to register swagger metadata in custom decorators by providing an array of `enhancers`.
We now add metadata with the `MarkdownBody` decorator: The request needs a `body` with content-type `text/markdown`.

Signed-off-by: David Mehren <[email protected]>
davidmehren added a commit to hedgedoc/hedgedoc that referenced this issue Jan 23, 2022
As explained in nestjs/swagger#32 (comment), it's possible to register swagger metadata in custom decorators by providing an array of `enhancers`.
We now add metadata with the `MarkdownBody` decorator: The request needs a `body` with content-type `text/markdown`.

Signed-off-by: David Mehren <[email protected]>
davidmehren added a commit to hedgedoc/hedgedoc that referenced this issue Jan 23, 2022
As explained in nestjs/swagger#32 (comment), it's possible to register swagger metadata in custom decorators by providing an array of `enhancers`.
We now add metadata with the `MarkdownBody` decorator: The request needs a `body` with content-type `text/markdown`.

Signed-off-by: David Mehren <[email protected]>
davidmehren added a commit to hedgedoc/hedgedoc that referenced this issue Jan 23, 2022
As explained in nestjs/swagger#32 (comment), it's possible to register swagger metadata in custom decorators by providing an array of `enhancers`.
We now add metadata with the `MarkdownBody` decorator: The request needs a `body` with content-type `text/markdown`.

Signed-off-by: David Mehren <[email protected]>
davidmehren added a commit to hedgedoc/hedgedoc that referenced this issue Jan 23, 2022
As explained in nestjs/swagger#32 (comment), it's possible to register swagger metadata in custom decorators by providing an array of `enhancers`.
We now add metadata with the `MarkdownBody` decorator: The request needs a `body` with content-type `text/markdown`.

Signed-off-by: David Mehren <[email protected]>
davidmehren added a commit to hedgedoc/hedgedoc that referenced this issue Jan 23, 2022
As explained in nestjs/swagger#32 (comment), it's possible to register swagger metadata in custom decorators by providing an array of `enhancers`.
We now add metadata with the `MarkdownBody` decorator: The request needs a `body` with content-type `text/markdown`.

Signed-off-by: David Mehren <[email protected]>
davidmehren added a commit to hedgedoc/hedgedoc that referenced this issue Jan 23, 2022
As explained in nestjs/swagger#32 (comment), it's possible to register swagger metadata in custom decorators by providing an array of `enhancers`.
We now add metadata with the `MarkdownBody` decorator: The request needs a `body` with content-type `text/markdown`.

Signed-off-by: David Mehren <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants