diff --git a/openapi/src/main/kotlin/de/codecentric/hikaku/converters/openapi/OpenApiConverter.kt b/openapi/src/main/kotlin/de/codecentric/hikaku/converters/openapi/OpenApiConverter.kt index 084c90df..890c54b1 100644 --- a/openapi/src/main/kotlin/de/codecentric/hikaku/converters/openapi/OpenApiConverter.kt +++ b/openapi/src/main/kotlin/de/codecentric/hikaku/converters/openapi/OpenApiConverter.kt @@ -59,13 +59,17 @@ class OpenApiConverter private constructor(private val specificationContent: Str val extractPathParameters = PathParameterExtractor(openApi) return openApi.paths.flatMap { (path, pathItem) -> + val commonQueryParameters = extractQueryParameters(pathItem.parameters) + val commonPathParameters = extractPathParameters(pathItem.parameters) + val commonHeaderParameters = extractHeaderParameters(pathItem.parameters) + pathItem.httpMethods().map { (httpMethod: HttpMethod, operation: Operation?) -> Endpoint( path = path, httpMethod = httpMethod, - queryParameters = extractQueryParameters(operation), - pathParameters = extractPathParameters(operation), - headerParameters = extractHeaderParameters(operation), + queryParameters = commonQueryParameters.union(extractQueryParameters(operation?.parameters)), + pathParameters = commonPathParameters.union(extractPathParameters(operation?.parameters)), + headerParameters = commonHeaderParameters.union(extractHeaderParameters(operation?.parameters)), consumes = extractConsumesMediaTypes(operation), produces = extractProduceMediaTypes(operation), deprecated = operation?.deprecated ?: false diff --git a/openapi/src/main/kotlin/de/codecentric/hikaku/converters/openapi/extractors/HeaderParameterExtractor.kt b/openapi/src/main/kotlin/de/codecentric/hikaku/converters/openapi/extractors/HeaderParameterExtractor.kt index f2b64392..317b4cd3 100644 --- a/openapi/src/main/kotlin/de/codecentric/hikaku/converters/openapi/extractors/HeaderParameterExtractor.kt +++ b/openapi/src/main/kotlin/de/codecentric/hikaku/converters/openapi/extractors/HeaderParameterExtractor.kt @@ -3,27 +3,25 @@ package de.codecentric.hikaku.converters.openapi.extractors import de.codecentric.hikaku.converters.openapi.extensions.referencedSchema import de.codecentric.hikaku.endpoints.HeaderParameter import io.swagger.v3.oas.models.OpenAPI -import io.swagger.v3.oas.models.Operation import io.swagger.v3.oas.models.parameters.Parameter as OpenApiParameter import io.swagger.v3.oas.models.parameters.HeaderParameter as OpenApiHeaderParameter internal class HeaderParameterExtractor(private val openApi: OpenAPI) { - operator fun invoke(operation: Operation?): Set { - return extractInlineHeaderParameters(operation).union(extractHeaderParametersFromComponents(operation)) + operator fun invoke(parameters: List?): Set { + return extractInlineHeaderParameters(parameters).union(extractHeaderParametersFromComponents(parameters)) } - private fun extractInlineHeaderParameters(operation: Operation?): Set { - return operation?.parameters + private fun extractInlineHeaderParameters(parameters: List?): Set { + return parameters ?.filterIsInstance() ?.map { HeaderParameter(it.name, it.required) } .orEmpty() .toSet() } - private fun extractHeaderParametersFromComponents(operation: Operation?): Set { - return operation?.parameters - ?.filterIsInstance() + private fun extractHeaderParametersFromComponents(parameters: List?): Set { + return parameters ?.filter { it.referencedSchema != null } ?.map { Regex("#/components/parameters/(?.+)") diff --git a/openapi/src/main/kotlin/de/codecentric/hikaku/converters/openapi/extractors/PathParameterExtractor.kt b/openapi/src/main/kotlin/de/codecentric/hikaku/converters/openapi/extractors/PathParameterExtractor.kt index df2a6a54..fbfbfba8 100644 --- a/openapi/src/main/kotlin/de/codecentric/hikaku/converters/openapi/extractors/PathParameterExtractor.kt +++ b/openapi/src/main/kotlin/de/codecentric/hikaku/converters/openapi/extractors/PathParameterExtractor.kt @@ -3,27 +3,25 @@ package de.codecentric.hikaku.converters.openapi.extractors import de.codecentric.hikaku.converters.openapi.extensions.referencedSchema import de.codecentric.hikaku.endpoints.PathParameter import io.swagger.v3.oas.models.OpenAPI -import io.swagger.v3.oas.models.Operation import io.swagger.v3.oas.models.parameters.PathParameter as OpenApiPathParameter import io.swagger.v3.oas.models.parameters.Parameter as OpenApiParameter internal class PathParameterExtractor(private val openApi: OpenAPI) { - operator fun invoke(operation: Operation?): Set { - return extractInlinePathParameters(operation).union(extractPathParametersFromComponents(operation)) + operator fun invoke(parameters: List?): Set { + return extractInlinePathParameters(parameters).union(extractPathParametersFromComponents(parameters)) } - private fun extractInlinePathParameters(operation: Operation?): Set { - return operation?.parameters + private fun extractInlinePathParameters(parameters: List?): Set { + return parameters ?.filterIsInstance() ?.map { PathParameter(it.name) } .orEmpty() .toSet() } - private fun extractPathParametersFromComponents(operation: Operation?): Set { - return operation?.parameters - ?.filterIsInstance() + private fun extractPathParametersFromComponents(parameters: List?): Set { + return parameters ?.filter { it.referencedSchema != null } ?.map { Regex("#/components/parameters/(?.+)") diff --git a/openapi/src/main/kotlin/de/codecentric/hikaku/converters/openapi/extractors/QueryParameterExtractor.kt b/openapi/src/main/kotlin/de/codecentric/hikaku/converters/openapi/extractors/QueryParameterExtractor.kt index 13609015..a43d9908 100644 --- a/openapi/src/main/kotlin/de/codecentric/hikaku/converters/openapi/extractors/QueryParameterExtractor.kt +++ b/openapi/src/main/kotlin/de/codecentric/hikaku/converters/openapi/extractors/QueryParameterExtractor.kt @@ -3,27 +3,25 @@ package de.codecentric.hikaku.converters.openapi.extractors import de.codecentric.hikaku.converters.openapi.extensions.referencedSchema import de.codecentric.hikaku.endpoints.QueryParameter import io.swagger.v3.oas.models.OpenAPI -import io.swagger.v3.oas.models.Operation import io.swagger.v3.oas.models.parameters.Parameter as OpenApiParameter import io.swagger.v3.oas.models.parameters.QueryParameter as OpenApiQueryParameter internal class QueryParameterExtractor(private val openApi: OpenAPI) { - operator fun invoke(operation: Operation?): Set { - return extractInlineQueryParameters(operation).union(extractQueryParametersFromComponents(operation)) + operator fun invoke(parameters: List?): Set { + return extractInlineQueryParameters(parameters).union(extractQueryParametersFromComponents(parameters)) } - private fun extractInlineQueryParameters(operation: Operation?): Set { - return operation?.parameters + private fun extractInlineQueryParameters(parameters: List?): Set { + return parameters ?.filterIsInstance() ?.map { QueryParameter(it.name, it.required) } .orEmpty() .toSet() } - private fun extractQueryParametersFromComponents(operation: Operation?): Set { - return operation?.parameters - ?.filterIsInstance() + private fun extractQueryParametersFromComponents(parameters: List?): Set { + return parameters ?.filter { it.referencedSchema != null } ?.map { Regex("#/components/parameters/(?.+)") diff --git a/openapi/src/test/kotlin/de/codecentric/hikaku/converters/openapi/OpenApiConverterHeaderParameterTest.kt b/openapi/src/test/kotlin/de/codecentric/hikaku/converters/openapi/OpenApiConverterHeaderParameterTest.kt index e23595ef..d1d0dd6e 100644 --- a/openapi/src/test/kotlin/de/codecentric/hikaku/converters/openapi/OpenApiConverterHeaderParameterTest.kt +++ b/openapi/src/test/kotlin/de/codecentric/hikaku/converters/openapi/OpenApiConverterHeaderParameterTest.kt @@ -38,4 +38,36 @@ class OpenApiConverterHeaderParameterTest { //then assertThat(result).containsExactlyInAnyOrderElementsOf(headerParameters) } + + @Test + fun `common header parameter inline declaration on Operation object`() { + //given + val file = Paths.get(this::class.java.classLoader.getResource("header_parameter/common_header_parameter_inline.yaml").toURI()) + val headerParameters = setOf( + HeaderParameter("x-b3-traceid", false), + HeaderParameter("allow-cache", true) + ) + + //when + val result = OpenApiConverter(file).conversionResult.toList()[0].headerParameters + + //then + assertThat(result).containsExactlyInAnyOrderElementsOf(headerParameters) + } + + @Test + fun `one common header parameter declared inline and one parameter referenced from parameters section in components`() { + //given + val file = Paths.get(this::class.java.classLoader.getResource("header_parameter/common_header_parameter_in_components.yaml").toURI()) + val headerParameters = setOf( + HeaderParameter("x-b3-traceid", false), + HeaderParameter("allow-cache", true) + ) + + //when + val result = OpenApiConverter(file).conversionResult.toList()[0].headerParameters + + //then + assertThat(result).containsExactlyInAnyOrderElementsOf(headerParameters) + } } \ No newline at end of file diff --git a/openapi/src/test/kotlin/de/codecentric/hikaku/converters/openapi/OpenApiConverterPathParameterTest.kt b/openapi/src/test/kotlin/de/codecentric/hikaku/converters/openapi/OpenApiConverterPathParameterTest.kt index e47073d0..a75c2437 100644 --- a/openapi/src/test/kotlin/de/codecentric/hikaku/converters/openapi/OpenApiConverterPathParameterTest.kt +++ b/openapi/src/test/kotlin/de/codecentric/hikaku/converters/openapi/OpenApiConverterPathParameterTest.kt @@ -36,4 +36,34 @@ class OpenApiConverterPathParameterTest { assertThat(result[1].pathParameters).containsExactly(pathParameter) assertThat(result[2].pathParameters).containsExactly(pathParameter) } + + @Test + fun `common path parameter inline declaration`() { + //given + val file = Paths.get(this::class.java.classLoader.getResource("path_parameter/common_path_parameter_inline.yaml").toURI()) + val pathParameter = PathParameter("id") + + //when + val result = OpenApiConverter(file).conversionResult.toList() + + //then + assertThat(result[0].pathParameters).containsExactly(pathParameter) + assertThat(result[1].pathParameters).containsExactly(pathParameter) + assertThat(result[2].pathParameters).containsExactly(pathParameter) + } + + @Test + fun `common path parameter referenced from parameters section in components`() { + //given + val file = Paths.get(this::class.java.classLoader.getResource("path_parameter/common_path_parameter_in_components.yaml").toURI()) + val pathParameter = PathParameter("id") + + //when + val result = OpenApiConverter(file).conversionResult.toList() + + //then + assertThat(result[0].pathParameters).containsExactly(pathParameter) + assertThat(result[1].pathParameters).containsExactly(pathParameter) + assertThat(result[2].pathParameters).containsExactly(pathParameter) + } } \ No newline at end of file diff --git a/openapi/src/test/kotlin/de/codecentric/hikaku/converters/openapi/OpenApiConverterQueryParameterTest.kt b/openapi/src/test/kotlin/de/codecentric/hikaku/converters/openapi/OpenApiConverterQueryParameterTest.kt index c792a6ac..f6b1db6a 100644 --- a/openapi/src/test/kotlin/de/codecentric/hikaku/converters/openapi/OpenApiConverterQueryParameterTest.kt +++ b/openapi/src/test/kotlin/de/codecentric/hikaku/converters/openapi/OpenApiConverterQueryParameterTest.kt @@ -38,4 +38,36 @@ class OpenApiConverterQueryParameterTest { //then assertThat(result).containsExactlyInAnyOrderElementsOf(queryParameters) } + + @Test + fun `common query parameter inline declaration on Operation object`() { + //given + val file = Paths.get(this::class.java.classLoader.getResource("query_parameter/common_query_parameter_inline.yaml").toURI()) + val queryParameters = setOf( + QueryParameter("tag", false), + QueryParameter("limit", true) + ) + + //when + val result = OpenApiConverter(file).conversionResult.toList()[0].queryParameters + + //then + assertThat(result).containsExactlyInAnyOrderElementsOf(queryParameters) + } + + @Test + fun `one query parameter declared inline and one common parameter referenced from parameters section in components`() { + //given + val file = Paths.get(this::class.java.classLoader.getResource("query_parameter/common_query_parameter_in_components.yaml").toURI()) + val queryParameters = setOf( + QueryParameter("tag", false), + QueryParameter("limit", true) + ) + + //when + val result = OpenApiConverter(file).conversionResult.toList()[0].queryParameters + + //then + assertThat(result).containsExactlyInAnyOrderElementsOf(queryParameters) + } } \ No newline at end of file diff --git a/openapi/src/test/resources/header_parameter/common_header_parameter_in_components.yaml b/openapi/src/test/resources/header_parameter/common_header_parameter_in_components.yaml new file mode 100644 index 00000000..d9161061 --- /dev/null +++ b/openapi/src/test/resources/header_parameter/common_header_parameter_in_components.yaml @@ -0,0 +1,28 @@ +openapi: 3.0.2 +info: + version: 1.0.0 + title: Todo List +paths: + /todos: + parameters: + - name: x-b3-traceid + in: header + required: false + description: "Trace id." + schema: + type: string + - $ref: "#/components/parameters/allowCacheParam" + get: + description: 'Get all todos' + responses: + '200': + description: OK +components: + parameters: + allowCacheParam: + name: allow-cache + in: header + required: true + description: "Whether cached data is allowed or not." + schema: + type: boolean \ No newline at end of file diff --git a/openapi/src/test/resources/header_parameter/common_header_parameter_inline.yaml b/openapi/src/test/resources/header_parameter/common_header_parameter_inline.yaml new file mode 100644 index 00000000..65dae6fc --- /dev/null +++ b/openapi/src/test/resources/header_parameter/common_header_parameter_inline.yaml @@ -0,0 +1,24 @@ +openapi: 3.0.2 +info: + version: 1.0.0 + title: Todo List +paths: + /todos: + parameters: + - name: x-b3-traceid + in: header + required: false + description: "Trace id." + schema: + type: string + - name: allow-cache + in: header + required: true + description: "Whether cached data is allowed or not." + schema: + type: boolean + get: + description: 'Get all todos' + responses: + '200': + description: OK \ No newline at end of file diff --git a/openapi/src/test/resources/path_parameter/common_path_parameter_in_components.yaml b/openapi/src/test/resources/path_parameter/common_path_parameter_in_components.yaml new file mode 100644 index 00000000..0dc9a69d --- /dev/null +++ b/openapi/src/test/resources/path_parameter/common_path_parameter_in_components.yaml @@ -0,0 +1,33 @@ +openapi: 3.0.2 +info: + version: 1.0.0 + title: Todo List +paths: + /todos/{id}: + parameters: + - $ref: "#/components/parameters/todoIdParam" + get: + description: 'Get all todos' + responses: + '200': + description: OK + post: + description: 'Create a new todo.' + responses: + '200': + description: OK + delete: + description: 'Delete a todo entry.' + responses: + '200': + description: OK +components: + parameters: + todoIdParam: + name: id + in: path + required: true + description: "Identifier of a specific todo entry." + schema: + type: integer + format: int32 \ No newline at end of file diff --git a/openapi/src/test/resources/path_parameter/common_path_parameter_inline.yaml b/openapi/src/test/resources/path_parameter/common_path_parameter_inline.yaml new file mode 100644 index 00000000..2bcb789a --- /dev/null +++ b/openapi/src/test/resources/path_parameter/common_path_parameter_inline.yaml @@ -0,0 +1,29 @@ +openapi: 3.0.2 +info: + version: 1.0.0 + title: Todo List +paths: + /todos/{id}: + parameters: + - name: id + in: path + required: true + description: "Identifier of a specific todo entry." + schema: + type: integer + format: int32 + get: + description: 'Get all todos' + responses: + '200': + description: OK + post: + description: 'Create a new todo.' + responses: + '200': + description: OK + delete: + description: 'Delete a todo entry.' + responses: + '200': + description: OK \ No newline at end of file diff --git a/openapi/src/test/resources/query_parameter/common_query_parameter_in_components.yaml b/openapi/src/test/resources/query_parameter/common_query_parameter_in_components.yaml new file mode 100644 index 00000000..ea289f3d --- /dev/null +++ b/openapi/src/test/resources/query_parameter/common_query_parameter_in_components.yaml @@ -0,0 +1,30 @@ +openapi: 3.0.2 +info: + version: 1.0.0 + title: Todo List +paths: + /todos: + parameters: + - $ref: "#/components/parameters/limitParam" + get: + description: 'Get all todos' + parameters: + - name: tag + in: query + required: false + description: "Filter todos by a given tag." + schema: + type: string + responses: + '200': + description: OK +components: + parameters: + limitParam: + name: limit + in: query + required: true + description: "Limit" + schema: + type: number + format: int32 \ No newline at end of file diff --git a/openapi/src/test/resources/query_parameter/common_query_parameter_inline.yaml b/openapi/src/test/resources/query_parameter/common_query_parameter_inline.yaml new file mode 100644 index 00000000..d7d79f92 --- /dev/null +++ b/openapi/src/test/resources/query_parameter/common_query_parameter_inline.yaml @@ -0,0 +1,26 @@ +openapi: 3.0.2 +info: + version: 1.0.0 + title: Todo List +paths: + /todos: + parameters: + - name: limit + in: query + required: true + description: "Limit" + schema: + type: number + format: int32 + get: + description: 'Get all todos' + parameters: + - name: tag + in: query + required: false + description: "Filter todos by a given tag." + schema: + type: string + responses: + '200': + description: OK \ No newline at end of file