-
Notifications
You must be signed in to change notification settings - Fork 115
Open
Description
Issue
When exporting the openapi.json file, there are repeated definitions of schemas. In my real world case, it is turning what should be a ~3K lines of openapi.json into 30K lines, but I've tried to showcase a minimal example below.
Example
Controller
import { createZodDto } from '@anatine/zod-nestjs';
import { extendZodWithOpenApi } from '@anatine/zod-openapi';
import { Body, Controller, Get, Post } from '@nestjs/common';
import { ApiCreatedResponse, ApiOkResponse, ApiOperation } from '@nestjs/swagger';
import { RequestBodyValidator } from 'src/http/pipes/validator.body.request';
import { z } from 'zod';
extendZodWithOpenApi(z);
const bugResourceSchema = z.object({
id: z.string().uuid(),
attributes: z.object({
name: z.string().min(1).max(250, 'name cannot be longer than 250 characters')
.openapi({ description: 'Bug name', example: 'Bug 1' }),
}),
});
const bugDetailSchema = z.object({
data: bugResourceSchema,
});
class BugDetailResponse extends createZodDto(bugDetailSchema) {}
export const bugCreateSchema = z.object({
data: bugResourceSchema.omit({ id: true }),
});
export class BugCreateRequest extends createZodDto(bugCreateSchema) {}
@Controller('bug')
export class BugController {
constructor() {}
@Post()
@ApiOperation({ summary: 'Create a bug' })
@ApiCreatedResponse({ description: 'Bug has been successfully created.', type: BugDetailResponse })
async create(@Body(new RequestBodyValidator(bugCreateSchema)) request: BugCreateRequest): Promise<BugDetailResponse> {
return { data: { id: '1', attributes: { name: 'Bug 1' } } };
}
@Get(':id')
@ApiOperation({ summary: 'Fetch a bug' })
@ApiCreatedResponse({ description: 'The details of a bug', type: BugDetailResponse })
async detail(): Promise<BugDetailResponse> {
return { data: { id: '1', attributes: { name: 'Bug 1' } } };
}
}openapi.json generation
export() {
const config = new DocumentBuilder().build();
patchNestjsSwagger();
const doc = {
...SwaggerModule.createDocument(this.app, config),
openapi: '3.1.0',
};
writeFileSync('docs/openapi.json', JSON.stringify(doc));
}Resulting openapi.json
{
"openapi": "3.1.0",
"paths": {
"/bug": {
"post": {
"operationId": "BugController_create",
"summary": "Create a bug",
"parameters": [],
"requestBody": {
"required": true,
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/BugCreateRequest" } } }
},
"responses": {
"201": {
"description": "Bug has been successfully created.",
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/BugDetailResponse" } } }
}
}
},
},
"/bug/{id}": {
"get": {
"operationId": "BugController_detail",
"summary": "Fetch a bug",
"parameters": [],
"responses": {
"201": {
"description": "The details of a bug",
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/BugDetailResponse" } } }
}
}
}
},
},
"components": {
"schemas": {
"BugCreateRequest": {
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"attributes": {
"type": "object",
"properties": {
"name": { "type": "string", "minLength": 1, "maxLength": 250, "description": "Bug name", "example": "Bug 1", "required": true }
},
"required": true
}
}
}
},
"required": ["data"]
},
"BugDetailResponse": {
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"id": { "type": "string", "format": "uuid", "required": true },
"attributes": {
"type": "object",
"properties": {
"name": { "type": "string", "minLength": 1, "maxLength": 250, "description": "Bug name", "example": "Bug 1", "required": true }
},
"required": true
}
}
}
},
"required": ["data"]
},
}
}Expected
BugCreateRequest attributes and BugDetailResponse attributes refer to the same piece of json so that the attributes are not repeated.
Actual
BugCreateRequest attributes and BugDetailResponse redefine the attributes, resulting in duplicate JSON.
Again, small issue in this example, but i am getting much larger objects each repeated 10+ times in the doc. Is there a trick I can do to define a component and have it reused?
RyanMulready, Vahor and zekenie
Metadata
Metadata
Assignees
Labels
No labels