Reputation: 745
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"
]
}
}
}
Upvotes: 3
Views: 10668
Reputation: 11
No parameters because you did not use @ApiBody or @ApiQuery
ApiBody({ type: dtos.store })(Target, name, descriptor);
In here:
@ApiBody({ type: CreateChatMessageDto })
@Post()
create(@Body() createChatMessageDto: CreateChatMessageDto) {
return this.service.create(createChatMessageDto);
}
Upvotes: 1
Reputation: 1242
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
Upvotes: 4