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:
@ApiOperation
addTag
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