diff --git a/.codacy.yml b/.codacy.yml new file mode 100644 index 00000000..c8f59295 --- /dev/null +++ b/.codacy.yml @@ -0,0 +1,16 @@ +--- +# Codacy configuration. +# +# exclude_paths accepts glob patterns relative to the repository root and removes +# the matched files from static analysis. We exclude sources that only produce +# false positives for this project's conventions: +# +# * Gradle task glue classes: thin DefaultTask subclasses. Codacy flags them for +# "missing Javadoc", but this project does not use Javadoc, so the warning is +# noise rather than a real defect. +# * Generated test fixtures under src/test/resources: these are the generator's +# expected-output files (not hand-written source) and trip rules such as +# line-length that do not apply to generated code. +exclude_paths: + - 'scs-multiapi-gradle-plugin/src/main/groovy/com/sngular/api/generator/plugin/*Task.groovy' + - '**/src/test/resources/**' diff --git a/.gitignore b/.gitignore index 7ae836cc..667f6f84 100644 --- a/.gitignore +++ b/.gitignore @@ -44,3 +44,6 @@ pom.xml.bak *.bak scs-multiapi-maven-plugin/dependency-reduced-pom.xml + +# Internal analysis documents (not part of the plugin distribution) +SCS-MULTIAPI-6.3.3-CODEGEN-BLOCKER.md diff --git a/multiapi-engine/pom.xml b/multiapi-engine/pom.xml index ef7ec3f6..7b691435 100644 --- a/multiapi-engine/pom.xml +++ b/multiapi-engine/pom.xml @@ -4,7 +4,7 @@ com.sngular multiapi-engine - 6.4.0 + 6.4.1 jar diff --git a/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/common/tools/ModelBuilder.java b/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/common/tools/ModelBuilder.java index be8614ab..5e05f831 100644 --- a/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/common/tools/ModelBuilder.java +++ b/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/common/tools/ModelBuilder.java @@ -272,7 +272,7 @@ private static List processObjectProperty( final SchemaFieldObject field; if (ApiTool.hasRef(fieldBody)) { final var typeName = MapperUtil.getRefSchemaName(fieldBody, fieldName); - final var refSchema = totalSchemas.get(MapperUtil.getRefSchemaKey(fieldBody)); + var refSchema = totalSchemas.get(MapperUtil.getRefSchemaKey(fieldBody)); if (!antiLoopList.contains(typeName) && Objects.nonNull(refSchema) && ApiTool.hasType(refSchema) && ApiTool.hasItems(refSchema) || ApiTool.getRefValue(fieldBody).contains(fieldName)) { if (antiLoopList.contains(typeName) && ApiTool.getRefValue(fieldBody).contains(fieldName)) { diff --git a/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/common/tools/SchemaUtil.java b/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/common/tools/SchemaUtil.java index 5b8fb69a..95fd95ac 100644 --- a/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/common/tools/SchemaUtil.java +++ b/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/common/tools/SchemaUtil.java @@ -9,7 +9,9 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Iterator; import java.util.Map; +import java.util.Map.Entry; import java.util.Objects; import com.fasterxml.jackson.databind.JsonNode; @@ -34,10 +36,16 @@ public static JsonNode solveRef(final String refValue, final Map 1) { + solvedRef = solvedRef.findValue(MapperUtil.getKey(refValueArr[1])); + } + } + if (Objects.nonNull(solvedRef) && Objects.nonNull(actualFileBase)) { + resolveNestedFileRefs(solvedRef, actualFileBase); } } } else { @@ -46,6 +54,71 @@ public static JsonNode solveRef(final String refValue, final Map "SCHEMAS/SERVICE_TYPE" + */ + static String computeFileSchemaKey(final String refValue) { + try { + final String[] parts = refValue.split("/"); + final String lastRaw = parts[parts.length - 1]; + String lastName = lastRaw; + if (lastName.contains(".")) { + lastName = lastName.substring(0, lastName.indexOf('.')); + } + String category = parts.length >= 2 ? parts[parts.length - 2] : "schemas"; + if (".".equals(category) || "..".equals(category)) { + category = "schemas"; + } + return StringUtils.upperCase(category + "/" + StringCaseUtils.titleToSnakeCase(lastName)); + } catch (final Exception e) { + return null; + } + } + + private static URI resolveActualBaseUri(final URI rootFilePath, final String filePath) { + try { + final String cleaned = cleanUpPath(filePath).replace('\\', '/'); + final Path rootPath = Paths.get(rootFilePath); + if (Files.exists(rootPath) && Files.isDirectory(rootPath)) { + return rootPath.resolve(cleaned).normalize().getParent().toUri(); + } + final Path parent = rootPath.getParent(); + if (Objects.nonNull(parent)) { + return parent.resolve(cleaned).normalize().getParent().toUri(); + } + return null; + } catch (final Exception e) { + return null; + } + } + + private static void resolveNestedFileRefs(final JsonNode node, final URI baseUri) { + if (Objects.isNull(node) || !node.isObject()) { + return; + } + final Iterator> fields = node.fields(); + while (fields.hasNext()) { + final Entry field = fields.next(); + if (field.getValue().isObject() && field.getValue().has("$ref")) { + final String refVal = field.getValue().get("$ref").textValue(); + if (StringUtils.isNotEmpty(refVal) && !refVal.startsWith("#") && !refVal.startsWith("http")) { + try { + final URI nestedBase = resolveActualBaseUri(baseUri, refVal); + final JsonNode resolved = getPojoFromRef(baseUri, refVal); + if (Objects.nonNull(resolved)) { + field.setValue(resolved); + resolveNestedFileRefs(resolved, nestedBase); + } + } catch (final Exception ignored) { + } + } + } else { + resolveNestedFileRefs(field.getValue(), baseUri); + } + } + } + public static JsonNode getPojoFromRef(final URI rootFilePath, final String refPath) { final JsonNode schemaFile; try { diff --git a/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/openapi/utils/MapperPathUtil.java b/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/openapi/utils/MapperPathUtil.java index d1fa7daa..b8540ca6 100644 --- a/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/openapi/utils/MapperPathUtil.java +++ b/multiapi-engine/src/main/java/com/sngular/api/generator/plugin/openapi/utils/MapperPathUtil.java @@ -6,6 +6,7 @@ package com.sngular.api.generator.plugin.openapi.utils; +import java.net.URI; import java.nio.file.Path; import java.util.ArrayList; import java.util.Collection; @@ -15,6 +16,7 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Objects; +import java.util.Optional; import java.util.function.BiConsumer; import com.fasterxml.jackson.databind.JsonNode; @@ -223,11 +225,15 @@ private static List mapRequestObject( "InlineObject" + operationIdWithCap, globalObject, baseDir)) .build()); } else { - final var requestBodyNode = globalObject.getRequestBodyNode(MapperUtil.getRefSchemaKey(requestBody)).orElseThrow(); + final Optional requestBodyNode = globalObject.getRequestBodyNode(MapperUtil.getRefSchemaKey(requestBody)); + if (requestBodyNode.isEmpty()) { + return requestObjects; + } + final JsonNode actualRequestBody = requestBodyNode.get(); requestObjects.add(RequestObject.builder() .required(ApiTool.hasNode(requestBody, REQUIRED)) - .isFormData(ApiTool.getNode(requestBodyNode, CONTENT).has("multipart/form-data")) - .contentObjects(mapContentObject(specFile, ApiTool.getNode(requestBodyNode, CONTENT), + .isFormData(ApiTool.getNode(actualRequestBody, CONTENT).has("multipart/form-data")) + .contentObjects(mapContentObject(specFile, ApiTool.getNode(actualRequestBody, CONTENT), operationIdWithCap, globalObject, baseDir)) .build()); } @@ -242,8 +248,11 @@ private static List mapParameterObjects( if (Objects.nonNull(parameters) && !parameters.isEmpty()) { for (final JsonNode parameter : parameters) { if (ApiTool.hasRef(parameter)) { - final JsonNode refParameter = globalObject.getParameterNode(MapperUtil.getRefSchemaKey(parameter)).orElseThrow(); - parameterObjects.add(buildParameterObject(specFile, globalObject, refParameter, baseDir)); + final Optional optRefParameter = globalObject.getParameterNode(MapperUtil.getRefSchemaKey(parameter)); + if (optRefParameter.isEmpty()) { + continue; + } + parameterObjects.add(buildParameterObject(specFile, globalObject, optRefParameter.get(), baseDir)); } else if (ApiTool.hasNode(parameter, CONTENT)) { parameterObjects.addAll(buildParameterContent(contentClassName, parameter, specFile, globalObject, baseDir)); } else { @@ -344,7 +353,21 @@ private static void buildResponse( final JsonNode response) { var realResponse = response; if (ApiTool.hasRef(response)) { - realResponse = globalObject.getResponseNode(MapperUtil.getRefSchemaKey(response)).orElseThrow(); + final String refValue = ApiTool.getRefValue(response); + if (refValue.startsWith("#")) { + final Optional resolvedResponse = globalObject.getResponseNode(MapperUtil.getRefSchemaKey(response)); + if (resolvedResponse.isEmpty()) { + return; + } + realResponse = resolvedResponse.get(); + } else { + try { + final URI baseUri = baseDir.resolve(specFile.getFilePath()).getParent().toUri(); + realResponse = SchemaUtil.getPojoFromRef(baseUri, refValue); + } catch (final Exception e) { + return; + } + } } final String operationIdWithCap = operationId.substring(0, 1).toUpperCase() + operationId.substring(1); final var content = ApiTool.getNode(realResponse, CONTENT); @@ -427,6 +450,9 @@ private static JsonNode getRefSchema(JsonNode schema, SpecFile specFile, GlobalO if (refValue.contains("schemas")) { refSchema = SchemaUtil.solveRef(refValue, globalObject.getSchemaMap(), baseDir.resolve(specFile.getFilePath()).getParent().toUri()); + if (Objects.nonNull(refSchema) && !refValue.contains("#")) { + globalObject.getSchemaMap().put(inlinePojoName, refSchema); + } } else if (refValue.contains("requestBodies")) { refSchema = SchemaUtil.solveRef(refValue, globalObject.getRequestBodyMap(), baseDir.resolve(specFile.getFilePath()).getParent().toUri()); diff --git a/multiapi-engine/src/test/java/com/sngular/api/generator/plugin/openapi/OpenApiGeneratorFixtures.java b/multiapi-engine/src/test/java/com/sngular/api/generator/plugin/openapi/OpenApiGeneratorFixtures.java index 5403e541..7748c294 100644 --- a/multiapi-engine/src/test/java/com/sngular/api/generator/plugin/openapi/OpenApiGeneratorFixtures.java +++ b/multiapi-engine/src/test/java/com/sngular/api/generator/plugin/openapi/OpenApiGeneratorFixtures.java @@ -182,6 +182,20 @@ public final class OpenApiGeneratorFixtures { .clientPackage("com.sngular.multifileplugin.externalpathitemref.client") .modelNameSuffix("DTO").build()); + static final List TEST_NESTED_EXTERNAL_REFS = List + .of(SpecFile.builder().filePath("openapigenerator/testNestedExternalRefs/api-test.yml") + .apiPackage("com.sngular.multifileplugin.testnestedexternalref") + .modelPackage("com.sngular.multifileplugin.testnestedexternalref.model") + .modelNameSuffix("DTO") + .useLombokModelAnnotation(true).build()); + + static final List TEST_NO_CONTENT_RESPONSES = List + .of(SpecFile.builder().filePath("openapigenerator/testNoContentResponses/api-test.yml") + .apiPackage("com.sngular.multifileplugin.testnocontentresponses") + .modelPackage("com.sngular.multifileplugin.testnocontentresponses.model") + .modelNameSuffix("DTO") + .useLombokModelAnnotation(true).build()); + static final List TEST_ANY_OF_IN_RESPONSE = List .of(SpecFile.builder().filePath("openapigenerator/testAnyOfInResponse/api-test.yml") .apiPackage("com.sngular.multifileplugin.testanyofinresponse") @@ -1370,6 +1384,37 @@ static Function validateApiWithNoComponents() { } + static Function validateNestedExternalRefs() { + final String DEFAULT_TARGET_API = "generated/com/sngular/multifileplugin/testnestedexternalref"; + + final String DEFAULT_MODEL_API = "generated/com/sngular/multifileplugin/testnestedexternalref/model"; + + final String COMMON_PATH = "openapigenerator/testNestedExternalRefs/"; + + final List expectedTestApiFiles = List.of(COMMON_PATH + "assets/ServicesApi.java"); + + final List expectedTestApiModelFiles = List + .of(COMMON_PATH + "assets/InlineResponse200ListServicesDTO.java", COMMON_PATH + "assets/Service_typeDTO.java"); + + return path -> commonTest(path, expectedTestApiFiles, expectedTestApiModelFiles, DEFAULT_TARGET_API, + DEFAULT_MODEL_API, Collections.emptyList(), null); + } + + static Function validateNoContentResponses() { + final String DEFAULT_TARGET_API = "generated/com/sngular/multifileplugin/testnocontentresponses"; + + final String DEFAULT_MODEL_API = "generated/com/sngular/multifileplugin/testnocontentresponses/model"; + + final String COMMON_PATH = "openapigenerator/testNoContentResponses/"; + + final List expectedTestApiFiles = List.of(COMMON_PATH + "assets/ItemsApi.java"); + + final List expectedTestApiModelFiles = List.of(COMMON_PATH + "assets/ItemDTO.java"); + + return path -> commonTest(path, expectedTestApiFiles, expectedTestApiModelFiles, DEFAULT_TARGET_API, + DEFAULT_MODEL_API, Collections.emptyList(), null); + } + private static Boolean commonTest(final Path resultPath, final List expectedFile, final List expectedModelFiles, final String targetApi, final String targetModel, final List expectedExceptionFiles, final String targetException) { diff --git a/multiapi-engine/src/test/java/com/sngular/api/generator/plugin/openapi/OpenApiGeneratorTest.java b/multiapi-engine/src/test/java/com/sngular/api/generator/plugin/openapi/OpenApiGeneratorTest.java index 72588900..723356a0 100644 --- a/multiapi-engine/src/test/java/com/sngular/api/generator/plugin/openapi/OpenApiGeneratorTest.java +++ b/multiapi-engine/src/test/java/com/sngular/api/generator/plugin/openapi/OpenApiGeneratorTest.java @@ -93,6 +93,10 @@ static Stream fileSpecToProcess() { OpenApiGeneratorFixtures.validateWebhookPathCollision()), Arguments.of("testExternalPathItemRefsGeneration", OpenApiGeneratorFixtures.TEST_EXTERNAL_PATH_ITEM_REF_GENERATION, OpenApiGeneratorFixtures.validateExternalPathItemRefGeneration()), + Arguments.of("testNestedExternalRefs", OpenApiGeneratorFixtures.TEST_NESTED_EXTERNAL_REFS, + OpenApiGeneratorFixtures.validateNestedExternalRefs()), + Arguments.of("testNoContentResponses", OpenApiGeneratorFixtures.TEST_NO_CONTENT_RESPONSES, + OpenApiGeneratorFixtures.validateNoContentResponses()), Arguments.of("testAnyOfInResponse", OpenApiGeneratorFixtures.TEST_ANY_OF_IN_RESPONSE, OpenApiGeneratorFixtures.validateAnyOfInResponse()), Arguments.of("testOneOfInResponse", OpenApiGeneratorFixtures.TEST_ONE_OF_IN_RESPONSE, diff --git a/multiapi-engine/src/test/resources/openapigenerator/testNestedExternalRefs/api-test.yml b/multiapi-engine/src/test/resources/openapigenerator/testNestedExternalRefs/api-test.yml new file mode 100644 index 00000000..2ccacf17 --- /dev/null +++ b/multiapi-engine/src/test/resources/openapigenerator/testNestedExternalRefs/api-test.yml @@ -0,0 +1,23 @@ +--- +openapi: "3.0.0" +info: + version: 1.0.0 + title: Nested External Ref Test + license: + name: MIT +servers: + - url: http://localhost:8080/v1 +paths: + /services: + get: + summary: List all services + operationId: listServices + tags: + - services + responses: + '200': + description: A list of services + content: + application/json: + schema: + $ref: "schemas/Service.yml" diff --git a/multiapi-engine/src/test/resources/openapigenerator/testNestedExternalRefs/assets/InlineResponse200ListServicesDTO.java b/multiapi-engine/src/test/resources/openapigenerator/testNestedExternalRefs/assets/InlineResponse200ListServicesDTO.java new file mode 100644 index 00000000..e3fc7680 --- /dev/null +++ b/multiapi-engine/src/test/resources/openapigenerator/testNestedExternalRefs/assets/InlineResponse200ListServicesDTO.java @@ -0,0 +1,26 @@ +package com.sngular.multifileplugin.testnestedexternalref.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Builder; +import lombok.Value; +import lombok.extern.jackson.Jacksonized; + +@Value +public class InlineResponse200ListServicesDTO { + + @JsonProperty(value ="service_id") + private String service_id; + + @JsonProperty(value ="service_type") + private Service_typeDTO service_type; + + + @Builder + @Jacksonized + private InlineResponse200ListServicesDTO(String service_id, Service_typeDTO service_type) { + this.service_id = service_id; + this.service_type = service_type; + + } + +} diff --git a/multiapi-engine/src/test/resources/openapigenerator/testNestedExternalRefs/assets/Service_typeDTO.java b/multiapi-engine/src/test/resources/openapigenerator/testNestedExternalRefs/assets/Service_typeDTO.java new file mode 100644 index 00000000..e7afd75e --- /dev/null +++ b/multiapi-engine/src/test/resources/openapigenerator/testNestedExternalRefs/assets/Service_typeDTO.java @@ -0,0 +1,26 @@ +package com.sngular.multifileplugin.testnestedexternalref.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Builder; +import lombok.Value; +import lombok.extern.jackson.Jacksonized; + +@Value +public class Service_typeDTO { + + @JsonProperty(value ="type_code") + private Integer type_code; + + @JsonProperty(value ="type_name") + private String type_name; + + + @Builder + @Jacksonized + private Service_typeDTO(Integer type_code, String type_name) { + this.type_code = type_code; + this.type_name = type_name; + + } + +} diff --git a/multiapi-engine/src/test/resources/openapigenerator/testNestedExternalRefs/assets/ServicesApi.java b/multiapi-engine/src/test/resources/openapigenerator/testNestedExternalRefs/assets/ServicesApi.java new file mode 100644 index 00000000..e85b1d96 --- /dev/null +++ b/multiapi-engine/src/test/resources/openapigenerator/testNestedExternalRefs/assets/ServicesApi.java @@ -0,0 +1,46 @@ +package com.sngular.multifileplugin.testnestedexternalref; + +import java.util.Optional; +import java.util.List; +import java.util.Map; +import javax.validation.Valid; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import org.springframework.http.MediaType; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.context.request.NativeWebRequest; + +import com.sngular.multifileplugin.testnestedexternalref.model.InlineResponse200ListServicesDTO; + +public interface ServicesApi { + + /** + * GET /services: List all services + * @return A list of services; (status code 200) + */ + + @Operation( + operationId = "listServices", + summary = "List all services", + tags = {"services"}, + responses = { + @ApiResponse(responseCode = "200", description = "A list of services", content = @Content(mediaType = "application/json", schema = @Schema(implementation = InlineResponse200ListServicesDTO.class))) + } + ) + @RequestMapping( + method = RequestMethod.GET, + value = "/services", + produces = {"application/json"} + ) + + default ResponseEntity listServices() { + return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); + } + +} diff --git a/multiapi-engine/src/test/resources/openapigenerator/testNestedExternalRefs/schemas/Service.yml b/multiapi-engine/src/test/resources/openapigenerator/testNestedExternalRefs/schemas/Service.yml new file mode 100644 index 00000000..8ff24350 --- /dev/null +++ b/multiapi-engine/src/test/resources/openapigenerator/testNestedExternalRefs/schemas/Service.yml @@ -0,0 +1,7 @@ +--- +type: object +properties: + service_id: + type: string + service_type: + $ref: './ServiceType.yml' diff --git a/multiapi-engine/src/test/resources/openapigenerator/testNestedExternalRefs/schemas/ServiceType.yml b/multiapi-engine/src/test/resources/openapigenerator/testNestedExternalRefs/schemas/ServiceType.yml new file mode 100644 index 00000000..3ee826f5 --- /dev/null +++ b/multiapi-engine/src/test/resources/openapigenerator/testNestedExternalRefs/schemas/ServiceType.yml @@ -0,0 +1,8 @@ +--- +type: object +properties: + type_code: + type: integer + format: int32 + type_name: + type: string diff --git a/multiapi-engine/src/test/resources/openapigenerator/testNoContentResponses/api-test.yml b/multiapi-engine/src/test/resources/openapigenerator/testNoContentResponses/api-test.yml new file mode 100644 index 00000000..05ef0823 --- /dev/null +++ b/multiapi-engine/src/test/resources/openapigenerator/testNoContentResponses/api-test.yml @@ -0,0 +1,57 @@ +--- +openapi: "3.0.0" +info: + version: 1.0.0 + title: No Content Responses Test + license: + name: MIT +servers: + - url: http://localhost:8080/v1 +paths: + /items: + get: + summary: List items + operationId: listItems + tags: + - items + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Item' + '204': + $ref: '#/components/responses/NoContent' + '401': + $ref: '#/components/responses/Unauthorized' + /items/{itemId}: + delete: + summary: Delete item + operationId: deleteItem + tags: + - items + responses: + '204': + $ref: '#/components/responses/NoContent' + '404': + $ref: '#/components/responses/NotFound' +components: + schemas: + Item: + type: object + properties: + id: + type: integer + format: int32 + name: + type: string + responses: + NoContent: + description: No content + Unauthorized: + description: Unauthorized access + NotFound: + description: Resource not found diff --git a/multiapi-engine/src/test/resources/openapigenerator/testNoContentResponses/assets/ItemDTO.java b/multiapi-engine/src/test/resources/openapigenerator/testNoContentResponses/assets/ItemDTO.java new file mode 100644 index 00000000..0fb28d19 --- /dev/null +++ b/multiapi-engine/src/test/resources/openapigenerator/testNoContentResponses/assets/ItemDTO.java @@ -0,0 +1,26 @@ +package com.sngular.multifileplugin.testnocontentresponses.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Builder; +import lombok.Value; +import lombok.extern.jackson.Jacksonized; + +@Value +public class ItemDTO { + + @JsonProperty(value ="name") + private String name; + + @JsonProperty(value ="id") + private Integer id; + + + @Builder + @Jacksonized + private ItemDTO(String name, Integer id) { + this.name = name; + this.id = id; + + } + +} diff --git a/multiapi-engine/src/test/resources/openapigenerator/testNoContentResponses/assets/ItemsApi.java b/multiapi-engine/src/test/resources/openapigenerator/testNoContentResponses/assets/ItemsApi.java new file mode 100644 index 00000000..a87c7f5f --- /dev/null +++ b/multiapi-engine/src/test/resources/openapigenerator/testNoContentResponses/assets/ItemsApi.java @@ -0,0 +1,71 @@ +package com.sngular.multifileplugin.testnocontentresponses; + +import java.util.Optional; +import java.util.List; +import java.util.Map; +import javax.validation.Valid; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import org.springframework.http.MediaType; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.context.request.NativeWebRequest; + +import com.sngular.multifileplugin.testnocontentresponses.model.ItemDTO; + +public interface ItemsApi { + + /** + * GET /items: List items + * @return Successful response; (status code 200) No content; (status code 204) Unauthorized access; (status code 401) + */ + + @Operation( + operationId = "listItems", + summary = "List items", + tags = {"items"}, + responses = { + @ApiResponse(responseCode = "200", description = "Successful response", content = @Content(mediaType = "application/json", schema = @Schema(implementation = List.class))), + @ApiResponse(responseCode = "204", description = "No content"), + @ApiResponse(responseCode = "401", description = "Unauthorized access") + } + ) + @RequestMapping( + method = RequestMethod.GET, + value = "/items", + produces = {"application/json"} + ) + + default ResponseEntity> listItems() { + return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); + } + /** + * DELETE /items/{itemId}: Delete item + * @return No content; (status code 204) Resource not found; (status code 404) + */ + + @Operation( + operationId = "deleteItem", + summary = "Delete item", + tags = {"items"}, + responses = { + @ApiResponse(responseCode = "204", description = "No content"), + @ApiResponse(responseCode = "404", description = "Resource not found") + } + ) + @RequestMapping( + method = RequestMethod.DELETE, + value = "/items/{itemId}", + produces = {"application/json"} + ) + + default ResponseEntity deleteItem() { + return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); + } + +} diff --git a/scs-multiapi-gradle-plugin/build.gradle b/scs-multiapi-gradle-plugin/build.gradle index 67976a57..129e16cd 100644 --- a/scs-multiapi-gradle-plugin/build.gradle +++ b/scs-multiapi-gradle-plugin/build.gradle @@ -21,7 +21,7 @@ repositories { } group = 'com.sngular' -version = '6.4.0' +version = '6.4.1' def SCSMultiApiPluginGroupId = group def SCSMultiApiPluginVersion = version @@ -31,7 +31,7 @@ dependencies { shadow localGroovy() shadow gradleApi() - implementation 'com.sngular:multiapi-engine:6.4.0' + implementation 'com.sngular:multiapi-engine:6.4.1' testImplementation 'org.assertj:assertj-core:3.24.2' testImplementation 'com.puppycrawl.tools:checkstyle:10.12.3' testImplementation 'org.junit.platform:junit-platform-launcher:1.9.2' @@ -100,7 +100,7 @@ testing { integrationTest(JvmTestSuite) { dependencies { - implementation 'com.sngular:scs-multiapi-gradle-plugin:6.4.0' + implementation 'com.sngular:scs-multiapi-gradle-plugin:6.4.1' implementation 'org.assertj:assertj-core:3.24.2' } diff --git a/scs-multiapi-gradle-plugin/src/main/groovy/com/sngular/api/generator/plugin/AsyncApiTask.groovy b/scs-multiapi-gradle-plugin/src/main/groovy/com/sngular/api/generator/plugin/AsyncApiTask.groovy index 2eab7796..7261441e 100644 --- a/scs-multiapi-gradle-plugin/src/main/groovy/com/sngular/api/generator/plugin/AsyncApiTask.groovy +++ b/scs-multiapi-gradle-plugin/src/main/groovy/com/sngular/api/generator/plugin/AsyncApiTask.groovy @@ -19,7 +19,7 @@ import org.gradle.api.tasks.OutputDirectory import org.gradle.api.tasks.TaskAction import org.gradle.work.DisableCachingByDefault -@DisableCachingByDefault(because = "Generation depends on external spec files that are not declared as cacheable inputs") +@DisableCachingByDefault(because = "Generation depends on external spec files not declared as cacheable inputs") abstract class AsyncApiTask extends DefaultTask { @Optional diff --git a/scs-multiapi-gradle-plugin/src/main/groovy/com/sngular/api/generator/plugin/OpenApiTask.groovy b/scs-multiapi-gradle-plugin/src/main/groovy/com/sngular/api/generator/plugin/OpenApiTask.groovy index f5b13937..d31a2493 100644 --- a/scs-multiapi-gradle-plugin/src/main/groovy/com/sngular/api/generator/plugin/OpenApiTask.groovy +++ b/scs-multiapi-gradle-plugin/src/main/groovy/com/sngular/api/generator/plugin/OpenApiTask.groovy @@ -18,7 +18,7 @@ import org.gradle.api.tasks.OutputDirectory import org.gradle.api.tasks.TaskAction import org.gradle.work.DisableCachingByDefault -@DisableCachingByDefault(because = "Generation depends on external spec files that are not declared as cacheable inputs") +@DisableCachingByDefault(because = "Generation depends on external spec files not declared as cacheable inputs") abstract class OpenApiTask extends DefaultTask { @Optional diff --git a/scs-multiapi-maven-plugin/pom.xml b/scs-multiapi-maven-plugin/pom.xml index b9e8fd8b..6f3c5e7f 100644 --- a/scs-multiapi-maven-plugin/pom.xml +++ b/scs-multiapi-maven-plugin/pom.xml @@ -4,7 +4,7 @@ com.sngular scs-multiapi-maven-plugin - 6.4.0 + 6.4.1 maven-plugin AsyncApi - OpenApi Code Generator Maven Plugin @@ -271,7 +271,7 @@ com.sngular multiapi-engine - 6.4.0 + 6.4.1 org.apache.maven