Skip to content

Commit 39f6b86

Browse files
cnsgithubmduesterhoeft
authored andcommitted
Aggregate parameters & descriptions from multiple snippets (closes #63) (#69)
1 parent 875cc8d commit 39f6b86

File tree

4 files changed

+168
-16
lines changed

4 files changed

+168
-16
lines changed

restdocs-api-spec-openapi-generator/src/main/kotlin/com/epages/restdocs/apispec/openapi2/OpenApi20Generator.kt

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -276,14 +276,16 @@ object OpenApi20Generator {
276276
extractPathParameters(
277277
firstModelForPathAndMethod
278278
).plus(
279-
firstModelForPathAndMethod.request.requestParameters.map {
280-
requestParameterDescriptor2Parameter(
281-
it
282-
)
283-
}).plus(
284-
firstModelForPathAndMethod.request.headers.map {
285-
header2Parameter(it)
286-
}
279+
modelsWithSamePathAndMethod
280+
.flatMap { it.request.requestParameters }
281+
.distinctBy { it.name }
282+
.map { requestParameterDescriptor2Parameter(it)
283+
}).plus(
284+
modelsWithSamePathAndMethod
285+
.flatMap { it.request.headers }
286+
.distinctBy { it.name }
287+
.map { header2Parameter(it)
288+
}
287289
).plus(
288290
listOfNotNull<Parameter>(
289291
requestFieldDescriptor2Parameter(

restdocs-api-spec-openapi-generator/src/test/kotlin/com/epages/restdocs/apispec/openapi2/OpenApi20GeneratorTest.kt

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,23 @@ class OpenApi20GeneratorTest {
151151
thenValidateOpenApi(openapi)
152152
}
153153

154+
@Test
155+
fun `should aggregate requests with same path and method but different parameters`() {
156+
val api = givenResourcesWithSamePathAndContentTypeAndDifferentParameters()
157+
158+
val openapi = whenOpenApiObjectGenerated(api)
159+
160+
val params = openapi.getPath("/products/{id}").get.parameters
161+
162+
then(params).anyMatch { it.name == "id" }
163+
then(params).anyMatch { it.name == "locale" }
164+
then(params).anyMatch { it.name == "color" && it.description == "Changes the color of the product" }
165+
then(params).anyMatch { it.name == "Authorization" }
166+
then(params).hasSize(4) // should not contain duplicated parameter descriptions
167+
168+
thenValidateOpenApi(openapi)
169+
}
170+
154171
private fun whenOpenApiObjectGenerated(api: List<ResourceModel>): Swagger {
155172
val openapi = OpenApi20Generator.generate(
156173
resources = api,
@@ -421,6 +438,51 @@ class OpenApi20GeneratorTest {
421438
)
422439
}
423440

441+
private fun givenResourcesWithSamePathAndContentTypeAndDifferentParameters(): List<ResourceModel> {
442+
return listOf(
443+
ResourceModel(
444+
operationId = "test",
445+
summary = "summary",
446+
description = "description",
447+
privateResource = false,
448+
deprecated = false,
449+
tags = setOf("tag1", "tag2"),
450+
request = getProductRequest(),
451+
response = getProduct200Response(getProductPayloadExample())
452+
),
453+
ResourceModel(
454+
operationId = "test",
455+
summary = "summary",
456+
description = "description",
457+
privateResource = false,
458+
deprecated = false,
459+
tags = setOf("tag1", "tag2"),
460+
request = getProductRequest(),
461+
response = getProduct200Response(getProductPayloadExample())
462+
),
463+
ResourceModel(
464+
operationId = "test-1",
465+
summary = "summary 1",
466+
description = "description 1",
467+
privateResource = false,
468+
deprecated = false,
469+
tags = setOf("tag1", "tag2"),
470+
request = getProductRequestWithDifferentParameter("color", "Changes the color of the product"),
471+
response = getProduct200Response(getProductPayloadExample())
472+
),
473+
ResourceModel(
474+
operationId = "test-1",
475+
summary = "summary 1",
476+
description = "description 1",
477+
privateResource = false,
478+
deprecated = false,
479+
tags = setOf("tag1", "tag2"),
480+
request = getProductRequestWithDifferentParameter("color", "Modifies the color of the product"),
481+
response = getProduct200Response(getProductPayloadExample())
482+
)
483+
)
484+
}
485+
424486
private fun postProduct200Response(example: String): ResponseModel {
425487
return ResponseModel(
426488
status = 200,
@@ -553,6 +615,18 @@ class OpenApi20GeneratorTest {
553615
)
554616
}
555617

618+
private fun getProductRequestWithDifferentParameter(name: String, description: String): RequestModel {
619+
return getProductRequest().copy(requestParameters = listOf(
620+
ParameterDescriptor(
621+
name = name,
622+
description = description,
623+
type = "STRING",
624+
optional = true,
625+
ignored = false
626+
)
627+
))
628+
}
629+
556630
private fun getProductRequestWithBasicSecurity(): RequestModel {
557631
return RequestModel(
558632
path = "/products",

restdocs-api-spec-openapi3-generator/src/main/kotlin/com/epages/restdocs/apispec/openapi3/OpenApi3Generator.kt

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -224,21 +224,23 @@ object OpenApi3Generator {
224224
val firstModelForPathAndMethod = modelsWithSamePathAndMethod.first()
225225
return Operation().apply {
226226
operationId = firstModelForPathAndMethod.operationId
227-
summary = firstModelForPathAndMethod.summary
228-
description = firstModelForPathAndMethod.description
227+
summary = modelsWithSamePathAndMethod.map { it.summary }.find { !it.isNullOrBlank() }
228+
description = modelsWithSamePathAndMethod.map { it.description }.find { !it.isNullOrBlank() }
229229
tags = modelsWithSamePathAndMethod.flatMap { it.tags }.distinct().nullIfEmpty()
230230
deprecated = if (modelsWithSamePathAndMethod.all { it.deprecated }) true else null
231231
parameters =
232232
extractPathParameters(
233233
firstModelForPathAndMethod
234234
).plus(
235-
firstModelForPathAndMethod.request.requestParameters.map {
236-
requestParameterDescriptor2Parameter(
237-
it
238-
)
235+
modelsWithSamePathAndMethod
236+
.flatMap { it.request.requestParameters }
237+
.distinctBy { it.name }
238+
.map { requestParameterDescriptor2Parameter(it)
239239
}).plus(
240-
firstModelForPathAndMethod.request.headers.map {
241-
header2Parameter(it)
240+
modelsWithSamePathAndMethod
241+
.flatMap { it.request.headers }
242+
.distinctBy { it.name }
243+
.map { header2Parameter(it)
242244
}
243245
).nullIfEmpty()
244246
requestBody = resourceModelsToRequestBody(

restdocs-api-spec-openapi3-generator/src/test/kotlin/com/epages/restdocs/apispec/openapi3/OpenApi3GeneratorTest.kt

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,23 @@ class OpenApi3GeneratorTest {
119119
thenOpenApiSpecIsValid()
120120
}
121121

122+
@Test
123+
fun `should aggregate requests with same path and method but different parameters`() {
124+
givenResourcesWithSamePathAndContentTypeAndDifferentParameters()
125+
126+
whenOpenApiObjectGenerated()
127+
128+
val params = openApiJsonPathContext.read<List<Map<String, String>>>("paths./products/{id}.get.parameters.*")
129+
130+
then(params).anyMatch { it["name"] == "id" }
131+
then(params).anyMatch { it["name"] == "locale" }
132+
then(params).anyMatch { it["name"] == "color" && it["description"] == "Changes the color of the product" }
133+
then(params).anyMatch { it["name"] == "Authorization" }
134+
then(params).hasSize(4) // should not contain duplicated parameter descriptions
135+
136+
thenOpenApiSpecIsValid()
137+
}
138+
122139
fun thenGetProductByIdOperationIsValid() {
123140
val productGetByIdPath = "paths./products/{id}.get"
124141
then(openApiJsonPathContext.read<List<String>>("$productGetByIdPath.tags")).isNotNull()
@@ -243,6 +260,51 @@ class OpenApi3GeneratorTest {
243260
)
244261
}
245262

263+
private fun givenResourcesWithSamePathAndContentTypeAndDifferentParameters() {
264+
resources = listOf(
265+
ResourceModel(
266+
operationId = "test",
267+
summary = "summary",
268+
description = "description",
269+
privateResource = false,
270+
deprecated = false,
271+
tags = setOf("tag1", "tag2"),
272+
request = getProductRequest(),
273+
response = getProductResponse()
274+
),
275+
ResourceModel(
276+
operationId = "test",
277+
summary = "summary",
278+
description = "description",
279+
privateResource = false,
280+
deprecated = false,
281+
tags = setOf("tag1", "tag2"),
282+
request = getProductRequest(),
283+
response = getProductResponse()
284+
),
285+
ResourceModel(
286+
operationId = "test-1",
287+
summary = "summary 1",
288+
description = "description 1",
289+
privateResource = false,
290+
deprecated = false,
291+
tags = setOf("tag1", "tag2"),
292+
request = getProductRequestWithDifferentParameter("color", "Changes the color of the product"),
293+
response = getProductResponse()
294+
),
295+
ResourceModel(
296+
operationId = "test-1",
297+
summary = "summary 1",
298+
description = "description 1",
299+
privateResource = false,
300+
deprecated = false,
301+
tags = setOf("tag1", "tag2"),
302+
request = getProductRequestWithDifferentParameter("color", "Modifies the color of the product"),
303+
response = getProductResponse()
304+
)
305+
)
306+
}
307+
246308
private fun givenResourcesWithSamePathAndDifferentMethods() {
247309
resources = listOf(
248310
ResourceModel(
@@ -509,6 +571,18 @@ class OpenApi3GeneratorTest {
509571
)
510572
}
511573

574+
private fun getProductRequestWithDifferentParameter(name: String, description: String): RequestModel {
575+
return getProductRequest().copy(requestParameters = listOf(
576+
ParameterDescriptor(
577+
name = name,
578+
description = description,
579+
type = "STRING",
580+
optional = true,
581+
ignored = false
582+
)
583+
))
584+
}
585+
512586
private fun thenOpenApiSpecIsValid() {
513587
val messages = OpenAPIParser().readContents(openApiSpecJsonString, emptyList(), ParseOptions()).messages
514588
then(messages).describedAs("OpenAPI validation messages should be empty").isEmpty()

0 commit comments

Comments
 (0)