-
Notifications
You must be signed in to change notification settings - Fork 535
Description
Description
When using swagger-parser to resolve and bundle an OpenAPI specification that references external fragments, the library generates duplicate components with sequential suffixes (e.g., EmployeeInfo_1) even when there are no actual naming conflicts in the source files.
Affected Version
2.1.27
Steps to Reproduce
- Create a main OpenAPI specification file (main.yaml) that references schemas from an external fragment
- Create a fragment file (fragments.yaml) with a component used in multiple contexts:
2.1. As intermediate references in requests (PostEmployeeRequest → EmployeeInfo)
2.2. As direct references in responses (EmployeeInfo200 → EmployeeInfo)
2.3. As array element references (EmployeesInfoPage.content.items → EmployeeInfo) - Use swagger-parser to resolve and bundle the specification
- Observe that duplicate components with suffixes are generated
main.yaml
openapi: "3.0.0"
info:
title: Test API
version: 1.0.0
paths:
/employees:
post:
requestBody:
content:
application/json:
schema:
$ref: 'fragments.yaml#/components/schemas/PostEmployeeRequest'
responses:
'201':
$ref: 'fragments.yaml#/components/responses/EmployeeInfo201'
/employees/id:
put:
requestBody:
content:
application/json:
schema:
$ref: 'fragments.yaml#/components/schemas/PutEmployeeRequest'
responses:
'200':
$ref: 'fragments.yaml#/components/responses/EmployeeInfo200'
/employees/extended:
get:
responses:
'200':
content:
application/json:
schema:
$ref: 'fragments.yaml#/components/schemas/EmployeesInfoPage'
fragments.yaml
openapi: "3.0.0"
info:
title: Fragments
version: 1.0.0
components:
schemas:
EmployeeInfo:
required:
- email
- employeeId
type: object
properties:
employeeId:
type: string
description: Identifier of the employee.
example: 123e4567-e89b-12d3-a456-426614174000_1729785600000
email:
type: string
format: email
example: [email protected]
role:
type: string
enum: ["REQUESTER", "ADMIN", "DEVELOPER"]
example: ADMIN
description: Schema used for defining the principal information of an employee.
PostEmployeeRequest:
$ref: '#/components/schemas/EmployeeInfo'
PutEmployeeRequest:
$ref: '#/components/schemas/EmployeeInfo'
EmployeesInfoPage:
type: object
properties:
content:
type: array
items:
$ref: '#/components/schemas/EmployeeInfo'
totalElements:
type: integer
example: 100
responses:
EmployeeInfo200:
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/EmployeeInfo'
EmployeeInfo201:
description: Created
content:
application/json:
schema:
$ref: '#/components/schemas/EmployeeInfo'
Result (note "EmployeeInfo_1):
openapi: 3.0.0
info:
title: Test API
version: 1.0.0
servers:
- url: /
paths:
/employees:
post:
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/PostEmployeeRequest'
responses:
"201":
$ref: '#/components/responses/EmployeeInfo201'
/employees/id:
put:
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/PutEmployeeRequest'
responses:
"200":
$ref: '#/components/responses/EmployeeInfo200'
"201":
$ref: '#/components/responses/EmployeeInfo201'
/employees/extended:
get:
responses:
"200":
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/EmployeesInfoPage'
components:
schemas:
PostEmployeeRequest:
$ref: '#/components/schemas/EmployeeInfo'
EmployeeInfo:
required:
- email
- employeeId
type: object
properties:
employeeId:
type: string
description: Identifier of the employee.
example: 123e4567-e89b-12d3-a456-426614174000_1729785600000
email:
type: string
description: Email of the employee.
format: email
example: [email protected]
groupTags:
$ref: '#/components/schemas/ArrayOfGroups'
role:
type: string
description: "Role of the employee inside of PDH. Three possible values:\
\ REQUESTER, ADMIN and DEVELOPER"
example: ADMIN
enum:
- REQUESTER
- ADMIN
- DEVELOPER
description: Schema used for defining the principal information of an employee.
ArrayOfGroups:
type: array
description: Schema used for defining an array of groups
items:
$ref: '#/components/schemas/GroupTags'
GroupTags:
type: object
properties:
groupTag:
type: string
example: group-1
EmployeeInfo_1:
required:
- email
- employeeId
type: object
properties:
employeeId:
type: string
description: Identifier of the employee.
example: 123e4567-e89b-12d3-a456-426614174000_1729785600000
email:
type: string
description: Email of the employee.
format: email
example: [email protected]
groupTags:
$ref: '#/components/schemas/ArrayOfGroups'
role:
type: string
description: "Role of the employee inside of PDH. Three possible values:\
\ REQUESTER, ADMIN and DEVELOPER"
example: ADMIN
enum:
- REQUESTER
- ADMIN
- DEVELOPER
description: Schema used for defining the principal information of an employee.
PutEmployeeRequest:
$ref: '#/components/schemas/EmployeeInfo'
EmployeesInfoPage:
type: object
properties:
content:
type: array
items:
$ref: '#/components/schemas/EmployeeInfo_1'
pageResponse:
$ref: '#/components/schemas/PageResponse'
description: Schema used for defining a page of employees containing also pagination
metadata.
PageResponse:
type: object
properties:
totalElements:
type: integer
example: 100
size:
type: integer
example: 20
responses:
EmployeeInfo201:
description: Created
content:
application/json:
schema:
$ref: '#/components/schemas/EmployeeInfo'
EmployeeInfo200:
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/EmployeeInfo'
Expected Behavior
The bundled specification should contain only one EmployeeInfo component, since:
- All references point to the same component definition
- No naming conflicts exist in any source file
- The component is defined only once
Workaround Applied
To prevent automatic suffix generation and gain control over component naming:
1- Create context-specific components:
Use EmployeeInfoRequest for all request schemas
Use EmployeeInfo for all response schemas
- Update references by context:
Result: This prevents suffix generation but requires maintaining duplicate component definitions, significantly reducing maintainability.
Impact
This behavior forces developers to choose between:
- Accepting unpredictable component names with auto-generated suffixes
- Duplicating component definitions to control naming (reducing maintainability)
Actual Behavior
Swagger-parser generates a bundled specification with:
- EmployeeInfo (original component)
- EmployeeInfo_1 (duplicate with suffix)
- Request components (PostEmployeeRequest, PutEmployeeRequest) reference EmployeeInfo_1
- Response components reference the original EmployeeInfo
Checklist
- I have searched the existing issues and this is not a duplicate (although similar issues were reported -e.g. Duplicated schemas in parsed result #1081).
- I have provided sufficient information for maintainers to reproduce the issue.