diff --git a/.gitignore b/.gitignore index 918350386..a717b3852 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,12 @@ *.tar.gz *.rar +# IDE files # +*.iml + +# Maven build +target/ + # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* diff --git a/README.md b/README.md index eca8fd0d8..442973e32 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ # Backbase OpenApi Tools -The Backbase Open API Tools is a collection of tools created to work effeciently with OpenAPI +The Backbase Open API Tools is a collection of tools created to work efficiently with OpenAPI It currently consists of diff --git a/boat-engine/src/main/java/com/backbase/oss/boat/Exporter.java b/boat-engine/src/main/java/com/backbase/oss/boat/Exporter.java index d33d2f41f..57390663b 100644 --- a/boat-engine/src/main/java/com/backbase/oss/boat/Exporter.java +++ b/boat-engine/src/main/java/com/backbase/oss/boat/Exporter.java @@ -1,5 +1,7 @@ package com.backbase.oss.boat; +import static com.backbase.oss.boat.ExampleUtils.getExampleObject; + import com.backbase.oss.boat.loader.CachingResourceLoader; import com.backbase.oss.boat.loader.RamlResourceLoader; import com.backbase.oss.boat.transformers.Transformer; @@ -81,21 +83,38 @@ public class Exporter { public static final String NO_DESCRIPTION_AVAILABLE = "No description available"; private static ObjectMapper mapper = Utils.createObjectMapper(); - private static boolean addJavaTypeExtensions; + private final ExporterOptions exporterOptions; - private Exporter() { - throw new AssertionError("Private constructor"); + private Exporter(ExporterOptions exporterOptions) { + super(); + this.exporterOptions = exporterOptions; } + /** + * Better to use {@link #export(File, ExporterOptions)} + * + * @param inputFile The input file. + * @param addJavaTypeExtensions whether to annotate with x-java-type when json schema contains javaType. + * @param transformers a list of transformers. + * @return OpenApi + * @throws ExportException things going south. + */ public static OpenAPI export(File inputFile, boolean addJavaTypeExtensions, List transformers) throws ExportException { - OpenAPI exported = export(inputFile, addJavaTypeExtensions); - transformers.forEach(transformer -> transformer.transform(exported, new HashMap())); - return exported; - } + return export(inputFile, + new ExporterOptions().addJavaTypeExtensions(addJavaTypeExtensions).transformers(transformers)); + } - public static OpenAPI export(File inputFile, boolean addJavaTypeExtensions) throws ExportException { + /** + * Guesses the service name from the file path and calls {@link #export(String, File)}. + * + * @param inputFile The input file. + * @param options options. + * @return OpenApi + * @throws ExportException things going south. + */ + public static OpenAPI export(File inputFile, ExporterOptions options) throws ExportException { // Guess Service Name AtomicReference serviceName = new AtomicReference<>("serviceName"); @@ -105,11 +124,10 @@ public static OpenAPI export(File inputFile, boolean addJavaTypeExtensions) thro .findFirst() .ifPresent(s -> serviceName.set(s.replaceAll("-spec", "-service"))); - return export(serviceName.get(), inputFile, addJavaTypeExtensions); + return new Exporter(options).export(serviceName.get(), inputFile); } - public static OpenAPI export(String serviceName, File inputFile, boolean addJavaTypeExtensions) - throws ExportException { + public OpenAPI export(String serviceName, File inputFile) throws ExportException { File parentFile = inputFile.getParentFile(); URL baseUrl; @@ -145,7 +163,7 @@ public static OpenAPI export(String serviceName, File inputFile, boolean addJava baseUrl, components, ramlTypeReferences, - addJavaTypeExtensions); + exporterOptions.isAddJavaTypeExtensions()); assert ramlApi != null; Map types = collectTypesFromRamlSpec(ramlApi); @@ -166,7 +184,7 @@ public static OpenAPI export(String serviceName, File inputFile, boolean addJava List examples = typeDeclaration.examples().stream() .map(exampleSpec -> { return new Example() - .value(ExampleUtils.getExampleObject(exampleSpec, true)) + .value(getExampleObject(exampleSpec, exporterOptions.isConvertExamplesToYaml())) .summary(exampleSpec.name()); }) .collect(Collectors.toList()); @@ -230,11 +248,13 @@ public static OpenAPI export(String serviceName, File inputFile, boolean addJava } components.getSchemas().values().forEach(Utils::cleanUp); + exporterOptions.getTransformers().forEach(transformer -> transformer.transform(openAPI, new HashMap())); + return openAPI; } - private static Info setupInfo(Api ramlApi) { - String description = getDescription(ramlApi.description()); + private Info setupInfo(Api ramlApi) { + String description = getDescription(ramlApi.description()); // todo not used log.debug("Setup Description"); String value = ramlApi.version() != null ? ramlApi.version().value() : "1.0"; @@ -266,12 +286,12 @@ private static Info setupInfo(Api ramlApi) { return info; } - private static List setupTags(Api ramlApi) { + private List setupTags(Api ramlApi) { String title = ramlApi.title().value().toLowerCase(Locale.ROOT); return Collections.singletonList(new Tag().name(title)); } - private static String cleanupMarkdownString(String value) { + private String cleanupMarkdownString(String value) { StringBuilder stringBuilder = new StringBuilder(); String[] lines = value.split("\n"); for (int i = 0; i < lines.length; i++) { @@ -285,7 +305,7 @@ private static String cleanupMarkdownString(String value) { return stringBuilder.toString().trim(); } - private static void parseRamlTypeReferences(URL baseUrl, Map ramlTypeReferences, + private void parseRamlTypeReferences(URL baseUrl, Map ramlTypeReferences, JsonNode jsonNode) { if (jsonNode.hasNonNull("types")) { ObjectNode types = (ObjectNode) jsonNode.get("types"); @@ -323,7 +343,7 @@ private static void parseRamlTypeReferences(URL baseUrl, Map ram } - private static void parseRamlRefEntry(URL baseUrl, Map ramlTypeReferences, + private void parseRamlRefEntry(URL baseUrl, Map ramlTypeReferences, Map.Entry nodeEntry) { String key = nodeEntry.getKey(); JsonNode typeReference = nodeEntry.getValue(); @@ -343,7 +363,7 @@ private static void parseRamlRefEntry(URL baseUrl, Map ramlTypeR } } - private static Map collectTypesFromRamlSpec(Api ramlApi) { + private Map collectTypesFromRamlSpec(Api ramlApi) { Map types = new TreeMap<>(); for (Library library : ramlApi.uses()) { @@ -355,7 +375,7 @@ private static Map collectTypesFromRamlSpec(Api ramlApi return types; } - private static void validateRamlModelResult(File file, RamlModelResult ramlModelResult) throws ExportException { + private void validateRamlModelResult(File file, RamlModelResult ramlModelResult) throws ExportException { if (ramlModelResult.hasErrors()) { log.error("Error validating RAML document: {}", file); ramlModelResult.getValidationResults() @@ -368,7 +388,7 @@ private static void validateRamlModelResult(File file, RamlModelResult ramlModel } } - private static void convertResources(List resources, Paths paths, Components components, + private void convertResources(List resources, Paths paths, Components components, JsonSchemaToOpenApi jsonSchemaToOpenApi, List operations) throws ExportException, DerefenceException { for (Resource resource : resources) { @@ -387,7 +407,7 @@ private static void convertResources(List resources, Paths paths, Comp } } - private static PathItem convertResource(String resourcePath, Resource resource, Components components, + private PathItem convertResource(String resourcePath, Resource resource, Components components, JsonSchemaToOpenApi jsonSchemaToOpenApi, List operationss) throws ExportException, DerefenceException { PathItem pathItem = new PathItem(); @@ -398,7 +418,7 @@ private static PathItem convertResource(String resourcePath, Resource resource, return pathItem; } - private static void mapUriParameters(String resourcePath, Resource resource, PathItem pathItem, + private void mapUriParameters(String resourcePath, Resource resource, PathItem pathItem, Components components) { Resource current = resource; Resource parent = current.parentResource(); @@ -431,7 +451,7 @@ private static void mapUriParameters(String resourcePath, Resource resource, Pat * @param resource RAML Resource Item * @param pathItem Path Item mapped to RAML Resource with added path parameters */ - private static void resolveUnspecifiedPathParameters(Resource resource, PathItem pathItem) { + private void resolveUnspecifiedPathParameters(Resource resource, PathItem pathItem) { String resourcePath = resource.resourcePath(); Matcher matcher = placeholderPattern.matcher(resourcePath); while (matcher.find()) { @@ -458,7 +478,7 @@ private static void resolveUnspecifiedPathParameters(Resource resource, PathItem } } - private static void log(TypeDeclaration typeDeclaration) { + private void log(TypeDeclaration typeDeclaration) { String description = getDescription(typeDeclaration.description()); if (log.isDebugEnabled()) { log.debug("Type name: {} type: {} displayName: {} defaultValue: {} description: {}" @@ -469,11 +489,11 @@ private static void log(TypeDeclaration typeDeclaration) { } - private static String getDisplayName(AnnotableStringType parameter) { + private String getDisplayName(AnnotableStringType parameter) { return parameter != null ? parameter.value() : null; } - private static String getDescription(MarkdownString description) { + private String getDescription(MarkdownString description) { if (description == null) { return NO_DESCRIPTION_AVAILABLE; } @@ -481,7 +501,7 @@ private static String getDescription(MarkdownString description) { return StringEscapeUtils.unescapeJavaScript(result); } - private static void mapMethods(String resourcePath, Resource resource, PathItem pathItem, Components components, + private void mapMethods(String resourcePath, Resource resource, PathItem pathItem, Components components, JsonSchemaToOpenApi jsonSchemaToOpenApi, List operations) throws ExportException, DerefenceException { for (Method ramlMethod : resource.methods()) { @@ -526,7 +546,7 @@ private static void mapMethods(String resourcePath, Resource resource, PathItem } } - private static String getSummary(MarkdownString description) { + private String getSummary(MarkdownString description) { if (description == null) { return null; } @@ -538,7 +558,7 @@ private static String getSummary(MarkdownString description) { .orElse(null); } - private static String getOperationId(Resource resource, Method ramlMethod, List operations, String tag, + private String getOperationId(Resource resource, Method ramlMethod, List operations, String tag, RequestBody requestBody, String resourcePath) { AnnotableStringType annotableStringType = ramlMethod.displayName(); String httpMethod; @@ -604,11 +624,11 @@ private static String getOperationId(Resource resource, Method ramlMethod, List< return operationId; } - private static boolean operationIdExists(List operations, String finalOperationId) { + private boolean operationIdExists(List operations, String finalOperationId) { return operations.stream().anyMatch(operation -> operation.getOperationId().equals(finalOperationId)); } - private static void processMethodAnnotations(String resourcePath, Components components, Method ramlMethod, + private void processMethodAnnotations(String resourcePath, Components components, Method ramlMethod, PathItem.HttpMethod httpMethod, Operation operation, JsonSchemaToOpenApi jsonSchemaToOpenApi) throws ExportException { for (AnnotationRef annotationRef : ramlMethod.annotations()) { @@ -633,7 +653,7 @@ private static void processMethodAnnotations(String resourcePath, Components com } } - private static Schema getAnnotationSchema(String resourcePath, Components components, TypeDeclaration annotation, + private Schema getAnnotationSchema(String resourcePath, Components components, TypeDeclaration annotation, JsonSchemaToOpenApi jsonSchemaToOpenApi) throws ExportException { Schema annotationSchema; if (annotation instanceof JSONTypeDeclaration) { @@ -663,7 +683,7 @@ private static Schema getAnnotationSchema(String resourcePath, Components compon return annotationSchema; } - private static RequestBody convertRequestBody(Resource resource, Method ramlMethod, Components components, + private RequestBody convertRequestBody(Resource resource, Method ramlMethod, Components components, JsonSchemaToOpenApi jsonSchemaToOpenApi) throws DerefenceException, ExportException { if (ramlMethod.body() == null || ramlMethod.body().size() == 0) { return null; @@ -681,7 +701,7 @@ private static RequestBody convertRequestBody(Resource resource, Method ramlMeth return requestBody; } - private static void addQueryParameters(Method ramlMethod, ArrayList parameters, Components components) { + private void addQueryParameters(Method ramlMethod, ArrayList parameters, Components components) { ramlMethod.queryParameters().forEach(typeDeclaration -> { Parameter parameter = new QueryParameter(); convertTypeToParameter(typeDeclaration, parameter, components); @@ -689,7 +709,7 @@ private static void addQueryParameters(Method ramlMethod, ArrayList p }); } - private static void addHeaders(Method ramlMethod, ArrayList parameters, Components components) { + private void addHeaders(Method ramlMethod, ArrayList parameters, Components components) { ramlMethod.headers().forEach(type -> { Parameter parameter = new HeaderParameter(); convertTypeToParameter(type, parameter, components); @@ -697,7 +717,7 @@ private static void addHeaders(Method ramlMethod, ArrayList parameter }); } - private static void convertTypeToParameter(TypeDeclaration typeDeclaration, Parameter parameter, + private void convertTypeToParameter(TypeDeclaration typeDeclaration, Parameter parameter, Components components) { if (log.isDebugEnabled()) { log.debug("Converting Parameter from: {} with type: {} into: {}", typeDeclaration.name(), @@ -717,17 +737,18 @@ private static void convertTypeToParameter(TypeDeclaration typeDeclaration, Para parameter.setExamples(new LinkedHashMap<>()); typeDeclaration.examples().forEach(exampleSpec -> { Example example = new Example(); - example.setValue(ExampleUtils.getExampleObject(exampleSpec, true)); + example.setValue(getExampleObject(exampleSpec, true)); example.setSummary(exampleSpec.name()); parameter.getExamples().put(exampleSpec.name(), example); }); } else { - parameter.setExample(ExampleUtils.getExampleObject(typeDeclaration.example(), true)); + parameter.setExample( + getExampleObject(typeDeclaration.example(), true)); } } - private static ApiResponses mapResponses(Resource resource, Method ramlMethod, Components components, + private ApiResponses mapResponses(Resource resource, Method ramlMethod, Components components, JsonSchemaToOpenApi jsonSchemaToOpenApi) throws ExportException, DerefenceException { ApiResponses apiResponses = new ApiResponses(); for (Response ramlResponse : ramlMethod.responses()) { @@ -760,7 +781,7 @@ private static ApiResponses mapResponses(Resource resource, Method ramlMethod, C return apiResponses; } - private static MediaType convertBody(TypeDeclaration body, String name, Components components, + private MediaType convertBody(TypeDeclaration body, String name, Components components, JsonSchemaToOpenApi jsonSchemaToOpenApi) throws ExportException, DerefenceException { Schema bodySchema = null; MediaType mediaType = null; @@ -816,23 +837,23 @@ private static MediaType convertBody(TypeDeclaration body, String name, Componen return mediaType; } - private static void convertExamples(TypeDeclaration body, MediaType mediaType) { + private void convertExamples(TypeDeclaration body, MediaType mediaType) { if (body.examples() != null && !body.examples().isEmpty()) { body.examples().forEach(exampleSpec -> { Example example = new Example(); - example.setValue(ExampleUtils.getExampleObject(exampleSpec, true)); + example.setValue(getExampleObject(exampleSpec, exporterOptions.isConvertExamplesToYaml())); example.setSummary(exampleSpec.name()); mediaType.addExamples(exampleSpec.name(), example); mediaType.setExample(null); }); } else { mediaType.setExamples(null); - mediaType.setExample(ExampleUtils.getExampleObject(body.example(), true)); + mediaType.setExample(getExampleObject(body.example(), exporterOptions.isConvertExamplesToYaml())); } } - private static String getName(Resource resource, Method ramlMethod) { + private String getName(Resource resource, Method ramlMethod) { AnnotableStringType annotableStringType = resource.displayName(); if (annotableStringType != null) { String value = annotableStringType.value(); @@ -858,7 +879,7 @@ private static String replacePlaceHolder(String part) { } } - private static String getDescription(Response ramlResponse) { + private String getDescription(Response ramlResponse) { String description = getDescription(ramlResponse.description()); if (description == null) { description = "Automagically created by RAML to Open API Exporter. Update RAML to include proper description for each response!"; @@ -866,7 +887,7 @@ private static String getDescription(Response ramlResponse) { return description; } - private static String getDescription(Resource resource) { + private String getDescription(Resource resource) { String description = getDescription(resource.description()); if (description == null) { return "Generated description for " + resource.displayName().value() diff --git a/boat-engine/src/main/java/com/backbase/oss/boat/ExporterOptions.java b/boat-engine/src/main/java/com/backbase/oss/boat/ExporterOptions.java new file mode 100644 index 000000000..5aaedb926 --- /dev/null +++ b/boat-engine/src/main/java/com/backbase/oss/boat/ExporterOptions.java @@ -0,0 +1,53 @@ +package com.backbase.oss.boat; + +import com.backbase.oss.boat.transformers.Transformer; +import java.util.LinkedList; +import java.util.List; + +public class ExporterOptions { + + private boolean addJavaTypeExtensions; + + private boolean convertExamplesToYaml = true; + + private List transformers = new LinkedList<>(); + + public boolean isAddJavaTypeExtensions() { + return addJavaTypeExtensions; + } + + public void setAddJavaTypeExtensions(boolean addJavaTypeExtensions) { + this.addJavaTypeExtensions = addJavaTypeExtensions; + } + + public ExporterOptions addJavaTypeExtensions(boolean addJavaTypeExtensions) { + this.addJavaTypeExtensions = addJavaTypeExtensions; + return this; + } + + public boolean isConvertExamplesToYaml() { + return convertExamplesToYaml; + } + + public void setConvertExamplesToYaml(boolean convertExamplesToYaml) { + this.convertExamplesToYaml = convertExamplesToYaml; + } + + public ExporterOptions convertExamplesToYaml(boolean convertExamplesToYaml) { + this.convertExamplesToYaml = convertExamplesToYaml; + return this; + } + + public List getTransformers() { + return transformers; + } + + public void setTransformers(List transformers) { + this.transformers = transformers; + } + + public ExporterOptions transformers(List transformers) { + this.transformers = transformers; + return this; + } +} diff --git a/boat-engine/src/test/java/com/backbase/oss/boat/ExporterTest.java b/boat-engine/src/test/java/com/backbase/oss/boat/ExporterTest.java index 615f18751..a8d9c0073 100644 --- a/boat-engine/src/test/java/com/backbase/oss/boat/ExporterTest.java +++ b/boat-engine/src/test/java/com/backbase/oss/boat/ExporterTest.java @@ -31,6 +31,17 @@ public void testHelloWorld() throws Exception { validateExport(export); } + @Test + public void testWallet() throws Exception { + File inputFile = getFile("/raml-examples/backbase-wallet/presentation-client-api.raml"); + OpenAPI openAPI = Exporter.export(inputFile, new ExporterOptions() + .addJavaTypeExtensions(true) + .convertExamplesToYaml(false) + .transformers(Collections.singletonList(new Decomposer()))); + String export = SerializerUtils.toYamlString(openAPI); + validateExport(export); + } + @Test public void testBankingApi() throws Exception { diff --git a/boat-maven-plugin/README.md b/boat-maven-plugin/README.md index 6daf5678c..4b93ad204 100644 --- a/boat-maven-plugin/README.md +++ b/boat-maven-plugin/README.md @@ -34,10 +34,15 @@ Configuration example mock-api-server + User UserItem + + false + + false diff --git a/boat-maven-plugin/src/main/java/com/backbase/oss/boat/AbstractRamlToOpenApi.java b/boat-maven-plugin/src/main/java/com/backbase/oss/boat/AbstractRamlToOpenApi.java index 385a045e3..99c9f64ff 100644 --- a/boat-maven-plugin/src/main/java/com/backbase/oss/boat/AbstractRamlToOpenApi.java +++ b/boat-maven-plugin/src/main/java/com/backbase/oss/boat/AbstractRamlToOpenApi.java @@ -5,7 +5,6 @@ import com.backbase.oss.boat.transformers.Decomposer; import com.backbase.oss.boat.transformers.Deprecator; import com.backbase.oss.boat.transformers.LicenseAdder; -import com.backbase.oss.boat.transformers.Transformer; import com.fasterxml.jackson.databind.ObjectMapper; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.Operation; @@ -82,6 +81,9 @@ abstract class AbstractRamlToOpenApi extends AbstractMojo { @Parameter(property = "convertJsonExamplesToYaml", defaultValue = "true") protected boolean convertJsonExamplesToYaml; + @Parameter(property = "addJavaTypeExtensions", defaultValue = "true") + protected boolean addJavaTypeExtensions; + @Parameter(property = "appendDeprecatedMetadataInDescription", defaultValue = "true") protected boolean appendDeprecatedMetadataInDescription = true; @@ -158,23 +160,25 @@ protected File export(String name, Optional version, File ramlFile, File protected OpenAPI convert(String name, Optional version, File ramlFile) throws ExportException { - List transformers = new ArrayList<>(); + ExporterOptions options = new ExporterOptions() + .addJavaTypeExtensions(addJavaTypeExtensions) + .convertExamplesToYaml(convertJsonExamplesToYaml); if (removeDeprecated) { - transformers.add(new Deprecator()); + options.getTransformers().add(new Deprecator()); } if (decompose) { - transformers.add(new Decomposer()); + options.getTransformers().add(new Decomposer()); } if (!addAdditionalProperties.isEmpty()) { - transformers.add(new AdditionalPropertiesAdder(addAdditionalProperties)); + options.getTransformers().add(new AdditionalPropertiesAdder(addAdditionalProperties)); } if (licenseName != null && licenseUrl != null) { - transformers.add(new LicenseAdder(licenseName, licenseUrl)); + options.getTransformers().add(new LicenseAdder(licenseName, licenseUrl)); } - OpenAPI openApi = Exporter.export(ramlFile, convertJsonExamplesToYaml, transformers); + OpenAPI openApi = Exporter.export(ramlFile, options); pimpInfo(name, version, ramlFile, openApi); if (appendDeprecatedMetadataInDescription) { // Iterate over all operations and update the description diff --git a/boat-terminal/src/main/java/com/backbase/oss/boat/BoatTerminal.java b/boat-terminal/src/main/java/com/backbase/oss/boat/BoatTerminal.java index af42a1e6e..ac204288e 100644 --- a/boat-terminal/src/main/java/com/backbase/oss/boat/BoatTerminal.java +++ b/boat-terminal/src/main/java/com/backbase/oss/boat/BoatTerminal.java @@ -43,7 +43,7 @@ public static void main(String[] args) { if (!inputFile.exists()) { throw new ParseException("Input file does not exist"); } - OpenAPI openApi = Exporter.export(inputFile, true); + OpenAPI openApi = Exporter.export(inputFile, new ExporterOptions().convertExamplesToYaml(true)); String yaml = SerializerUtils.toYamlString(openApi); if (hasOutputFile) {