Skip to content

Commit a2e9b76

Browse files
committed
fix: should fail publication of package version with duplicated operations
1 parent e93491a commit a2e9b76

File tree

8 files changed

+138
-21
lines changed

8 files changed

+138
-21
lines changed

src/apitypes/graphql/graphql.operations.ts

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,6 @@ export const buildGraphQLOperations: OperationsBuilder<GraphApiSchema> = async (
6767
await asyncFunction(async () => {
6868
const operationId = slugify(`${GRAPHQL_TYPE[type]}-${operationKey}`)
6969

70-
if (ctx.operationResolver(operationId)) {
71-
notifications.push({
72-
severity: MESSAGE_SEVERITY.Error,
73-
message: `Duplicated operation with operationId = ${operationId} found`,
74-
operationId: operationId,
75-
})
76-
}
7770
syncDebugPerformance('[Operation]', (innerDebugCtx) =>
7871
logLongBuild(() => {
7972
const operation: VersionGraphQLOperation = buildGraphQLOperation(

src/apitypes/rest/rest.operations.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -82,12 +82,6 @@ export const buildRestOperations: OperationsBuilder<OpenAPIV3.Document> = async
8282
const basePath = extractOperationBasePath(methodData?.servers || pathData?.servers || servers || [])
8383
const operationId = calculateOperationId(basePath, key, path)
8484

85-
if (ctx.operationResolver(operationId)) {
86-
ctx.notifications.push({
87-
severity: MESSAGE_SEVERITY.Warning,
88-
message: `Duplicated operation with operationId = ${operationId} found`,
89-
})
90-
}
9185
syncDebugPerformance('[Operation]', (innerDebugCtx) =>
9286
logLongBuild(() => {
9387
const operation = buildRestOperation(

src/utils/document.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ export function toPackageDocument(document: VersionDocument): PackageDocument {
7676
export function setDocument(buildResult: BuildResult, document: VersionDocument, operations: ApiOperation[] = []): void {
7777
buildResult.documents.set(document.fileId, document)
7878
for (const operation of operations) {
79+
if (buildResult.operations.has(operation.operationId)) {
80+
throw new Error(`Duplicated operation with operationId '${operation.operationId}' found`)
81+
}
7982
buildResult.operations.set(operation.operationId, operation)
8083
}
8184
}
@@ -129,11 +132,11 @@ export interface BundlingError {
129132
export const createBundlingErrorHandler = (ctx: BuilderContext, fileId: FileId) => (errors: BundlingError[]): void => {
130133
// Only throw if severity is ERROR and there's at least one critical error
131134
if (ctx.config.validationRulesSeverity?.brokenRefs === VALIDATION_RULES_SEVERITY_LEVEL_ERROR) {
132-
const criticalError = errors.find(error =>
133-
error.errorType === RefErrorTypes.REF_NOT_FOUND ||
135+
const criticalError = errors.find(error =>
136+
error.errorType === RefErrorTypes.REF_NOT_FOUND ||
134137
error.errorType === RefErrorTypes.REF_NOT_VALID_FORMAT,
135138
)
136-
139+
137140
if (criticalError) {
138141
throw new Error(criticalError.message)
139142
}

test/bugs.test.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,4 +371,17 @@ describe('Operation Bugs', () => {
371371
],
372372
})).rejects.toThrow('Invalid path \'/res/data/{}\': path parameter name could not be empty')
373373
})
374+
375+
test('Should throw error if duplicated operation is found', async () => {
376+
const pkg = LocalRegistry.openPackage('duplicated-operation')
377+
378+
await expect(pkg.publish(pkg.packageId, {
379+
packageId: pkg.packageId,
380+
version: 'v1',
381+
files: [
382+
{ fileId: 'spec1.json' },
383+
{ fileId: 'spec2.json' },
384+
],
385+
})).rejects.toThrow('Duplicated operation with operationId \'res-data-post\' found')
386+
})
374387
})
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
{
2+
"openapi": "3.0.1",
3+
"info": {
4+
"title": "API",
5+
"description": "",
6+
"version": "3.0"
7+
},
8+
"paths": {
9+
"/res/data": {
10+
"post": {
11+
"summary": "Profile",
12+
"operationId": "createProfile",
13+
"requestBody": {
14+
"content": {
15+
"application/json": {
16+
"schema": {
17+
"type": "object"
18+
}
19+
}
20+
},
21+
"required": true
22+
},
23+
"responses": {
24+
"201": {
25+
"description": "Description",
26+
"content": {
27+
"application/json;charset=UTF-8": {
28+
"schema": {
29+
"type": "string"
30+
}
31+
}
32+
}
33+
}
34+
}
35+
}
36+
}
37+
}
38+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
{
2+
"openapi": "3.0.1",
3+
"info": {
4+
"title": "API",
5+
"description": "",
6+
"version": "3.0"
7+
},
8+
"paths": {
9+
"/res/data": {
10+
"post": {
11+
"summary": "Profile",
12+
"operationId": "createProfile",
13+
"requestBody": {
14+
"content": {
15+
"application/json": {
16+
"schema": {
17+
"type": "object"
18+
}
19+
}
20+
},
21+
"required": true
22+
},
23+
"responses": {
24+
"201": {
25+
"description": "Description",
26+
"content": {
27+
"application/json;charset=UTF-8": {
28+
"schema": {
29+
"type": "string"
30+
}
31+
}
32+
}
33+
}
34+
}
35+
}
36+
}
37+
}
38+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
{
2+
"openapi": "3.0.1",
3+
"info": {
4+
"title": "API",
5+
"description": "",
6+
"version": "3.0"
7+
},
8+
"paths": {
9+
"/res/data/{}": {
10+
"post": {
11+
"summary": "Profile",
12+
"operationId": "createProfile",
13+
"requestBody": {
14+
"content": {
15+
"application/json": {
16+
"schema": {
17+
"type": "object"
18+
}
19+
}
20+
},
21+
"required": true
22+
},
23+
"responses": {
24+
"201": {
25+
"description": "Description",
26+
"content": {
27+
"application/json;charset=UTF-8": {
28+
"schema": {
29+
"type": "string"
30+
}
31+
}
32+
}
33+
}
34+
}
35+
}
36+
}
37+
}
38+
}

test/projects/graphql/spec1.graphql

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,21 @@ directive @deprecated( reason: String = "No longer supported" ) on OBJECT | INPU
55
type Query
66
{
77
"""Get list of Pets"""
8-
listPets(listId: String):[Pet!]
8+
listPets1(listId: String):[Pet!]
99

1010
"""Get Pet by ID"""
11-
getPet(id: String!): Pet
11+
getPet1(id: String!): Pet
1212

1313
"""Get list of Users"""
14-
listUsers(listId: String):[User!]
14+
listUsers1(listId: String):[User!]
1515

1616
"""Get User by ID"""
17-
getUser(id: String!): User @deprecated (reason: "New query is developed")
17+
getUser1(id: String!): User @deprecated (reason: "New query is developed")
1818
}
1919

2020
type Mutation {
2121
"""Pet availability check"""
22-
petAvailabilityCheck2(input: AvailabilityCheckRequest): [AvailabilityCheckResult!]
22+
petAvailabilityCheck1(input: AvailabilityCheckRequest): [AvailabilityCheckResult!]
2323
}
2424

2525
"""Availability Check Request"""

0 commit comments

Comments
 (0)