Last active
October 23, 2024 21:54
-
-
Save MarZab/c6311f83dec6401966e847c55d81a9bb to your computer and use it in GitHub Desktop.
NestJS Filters with Swagger deepObject (example: `?filters[name]=thing1&filters[description]=thing2`)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { applyDecorators } from '@nestjs/common'; | |
import { ApiExtraModels, ApiQuery, getSchemaPath } from '@nestjs/swagger'; | |
/** | |
* Combines Swagger Decorators to create a description for `filters[name]=something` | |
* - has support for swagger | |
* - automatic transformation with nestjs | |
*/ | |
// eslint-disable-next-line @typescript-eslint/ban-types,@typescript-eslint/explicit-module-boundary-types | |
export function ApiFilterQuery(fieldName: string, filterDto: Function) { | |
return applyDecorators( | |
ApiExtraModels(filterDto), | |
ApiQuery({ | |
required: false, | |
name: fieldName, | |
style: 'deepObject', | |
explode: true, | |
type: 'object', | |
schema: { | |
$ref: getSchemaPath(filterDto), | |
}, | |
}), | |
); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Controller, Get, Query } from '@nestjs/common'; | |
import { ApiOperation } from '@nestjs/swagger'; | |
import { ApiFilterQuery } from './api-filter-query'; | |
import { ApiPropertyOptional } from '@nestjs/swagger'; | |
import { IsOptional, IsString } from 'class-validator'; | |
class ThingFiltersDto { | |
@ApiPropertyOptional({ description: 'Thing Name', example: 'Ficus' }) | |
@IsString() | |
@IsOptional() | |
readonly name?: string; | |
@ApiPropertyOptional({ description: 'Thing Description', example: 'Large' }) | |
@IsString() | |
@IsOptional() | |
readonly description?: string; | |
} | |
@Controller() | |
export class FlowerController { | |
@Get('things') | |
@ApiOperation({ summary: ' List/Filter' }) | |
@ApiFilterQuery('filters', ThingFiltersDto) | |
async list(@Query('filters') filters: ThingFiltersDto): Promise<void> { | |
console.log({ filters }); | |
// from: filters[name]=thing1&filters[description]=thing2 | |
// to: { name: "thing1", description: "thing2" | |
} | |
} |
perfect!
Thank you @MarZab for this very useful example!
To avoid the "eslint-disable-next-line", we can use Type
from @nestjs/common
instead of Function
.
I can't figure out how to use ApiNestedQuery decorator @gwythyr
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hello @MarZab
Here is an improvement of your initial idea, such decorator accepts a class and extracts all properties and corresponding types