I'm having an issue with Nest + Swagger. When I open my swagger docs I see all of the endpoints I expect but am having two issues:
No parameters despite having a DTO defined for the bodyUltimately I think the issue is: Swagger + Nest is not creating unique operationId's for each method. My understanding is that methods will only fail to get unique operationId's when they are not sufficiently unique: 2 methods with identical call signatures for example.
In the past when I've had issues like this it was either because I was missing the @ApiTags decorator, or I had accidentally included duplicate endpoints.
In general it feels like I missed a step in configuring Swagger, or I didn't set it up properly with Fastify. I installed fastify-swagger but I'm not actually using it anywhere, but according the docs on Nest's site the route for the swagger JSON should be /api/json when using Fastify, which it is for me.
Things that didn't work:
@ApiOperationaddTag to the DocumentBuilder chainswagger-ui-express and @nestjs/platform-express dependenciesUpdate:
Adding @ApiOperation({ operationId: 'test' }) to a method does fix this, but I was under impression that @nest/swagger did this automatically. Are my methods not unique enough?
main.ts
async function bootstrap() {
const app = await NestFactory.create<NestFastifyApplication>(
AppModule,
new FastifyAdapter(),
);
app.useGlobalPipes(
new ValidationPipe({
whitelist: true,
forbidNonWhitelisted: true,
transform: true,
}),
);
app.useGlobalInterceptors(new ClassSerializerInterceptor(app.get(Reflector))); // allows automatic serialization
app.enableCors();
const config = new DocumentBuilder().setTitle('PIM API').build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('docs', app, document);
await app.listen(process.env.APP_PORT || 3001);
}
bootstrap();
some controller
@ApiTags('chat-messages')
@Controller('chat-messages')
export class ChatMessagesController {
constructor(
private readonly service: ChatMessagesService,
) {}
@Post()
create(@Body() createChatMessageDto: CreateChatMessageDto) {
return this.service.create(createChatMessageDto);
}
@Get(':stream_id')
findByStreamId(@Param('stream_id') streamId: string) {
return this.service.findByStreamId(streamId);
}
ChatMessageDto
export class CreateChatMessageDto {
constructor(partial: Partial<CreateChatMessageDto>) {
Object.assign(this, partial);
}
@IsString()
value: string;
@IsRFC3339()
timestamp: Date;
@IsNotEmpty()
streamId: string;
}
Swagger JSON
{
"/chat-messages":{
"post":{
"operationId":"ChatMessagesController_",
"parameters":[
],
"responses":{
"201":{
"description":"",
"content":{
"application/json":{
"schema":{
"$ref":"#/components/schemas/ChatMessage"
}
}
}
}
},
"tags":[
"chat-messages"
]
}
},
"/chat-messages/{stream_id}":{
"get":{
"operationId":"ChatMessagesController_",
"parameters":[
],
"responses":{
"200":{
"description":"",
"content":{
"application/json":{
"schema":{
"type":"array",
"items":{
"$ref":"#/components/schemas/ChatMessage"
}
}
}
}
}
},
"tags":[
"chat-messages"
]
}
}
}
Did you try putting @ApiProperty in your dto ?
Like this:
export class CreateChatMessageDto {
constructor(partial: Partial<CreateChatMessageDto>) {
Object.assign(this, partial);
}
@ApiProperty()
@IsString()
value: string;
@ApiProperty()
@IsRFC3339()
timestamp: Date;
@ApiProperty()
@IsNotEmpty()
streamId: string;
}
This allows Swagger to see the properties. This is what NestJs recommends in their documentation See here
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With