126 lines
5.5 KiB
Java
126 lines
5.5 KiB
Java
package com.krusoe.openapimerge.merge;
|
|
|
|
import com.fasterxml.jackson.databind.DeserializationFeature;
|
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
import io.swagger.v3.core.util.Json;
|
|
import io.swagger.v3.oas.models.OpenAPI;
|
|
import io.swagger.v3.oas.models.PathItem;
|
|
import org.apache.commons.io.FileUtils;
|
|
import org.openapitools.codegen.validation.Invalid;
|
|
import org.openapitools.codegen.validation.ValidationRule;
|
|
import org.openapitools.codegen.validations.oas.OpenApiEvaluator;
|
|
import org.openapitools.codegen.validations.oas.RuleConfiguration;
|
|
import org.springframework.shell.command.annotation.Command;
|
|
import org.springframework.shell.command.annotation.Option;
|
|
|
|
import java.io.File;
|
|
import java.io.IOException;
|
|
import java.io.OutputStream;
|
|
import java.util.HashSet;
|
|
import java.util.Objects;
|
|
import java.util.Set;
|
|
import java.util.stream.Stream;
|
|
|
|
@Command
|
|
public class MergeCommand {
|
|
|
|
private ObjectMapper objectMapper = new ObjectMapper();
|
|
|
|
@Command(description = "Merge APIs")
|
|
public void merge(@Option(required = true, shortNames = {'d'}, longNames = {"dir"}) String dir, @Option(required = false, shortNames = {'o'}, longNames = {"out"}) String out) throws IOException {
|
|
File dirFile = new File(dir);
|
|
|
|
if (FileUtils.isDirectory(dirFile)) {
|
|
ApiSpec mergedSpec = new ApiSpec();
|
|
for (File processedFile : FileUtils.listFiles(dirFile, new String[]{".json"}, true)) {
|
|
System.out.println("Processing file: " + processedFile.getAbsolutePath());
|
|
|
|
ApiSpec currentFileSpec = objectMapper.readerFor(ApiSpec.class).readValue(processedFile);
|
|
|
|
mergedSpec.merge(currentFileSpec);
|
|
}
|
|
|
|
var outFile = new File(dirFile, "mergedapi.json");
|
|
if (outFile.exists()) {
|
|
outFile.delete();
|
|
}
|
|
System.out.println("Writing merged APIs");
|
|
try (OutputStream outStream = FileUtils.newOutputStream(outFile, false)) {
|
|
objectMapper.writerWithDefaultPrettyPrinter().writeValue(outStream, mergedSpec);
|
|
}
|
|
}
|
|
}
|
|
|
|
@Command(description = "Validate APIs")
|
|
public void validate(@Option(required = true, shortNames = {'f'}, longNames = {"file"}) String fileToBalidate) throws IOException {
|
|
File outFile = new File(fileToBalidate);
|
|
|
|
if (outFile.isDirectory()) {
|
|
System.out.println("Given file is an directory");
|
|
} else {
|
|
validateFile(outFile);
|
|
}
|
|
}
|
|
|
|
private void validateFile(File outFile) throws IOException {
|
|
if (outFile.exists()) {
|
|
System.out.println("Validating OpenAPI file " + outFile.getAbsolutePath());
|
|
OpenApiEvaluator evaluator = new OpenApiEvaluator(new RuleConfiguration());
|
|
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
|
OpenAPI validatedApi = Json.mapper().readValue(outFile, OpenAPI.class);
|
|
|
|
|
|
var validationResult = evaluator.validate(validatedApi);
|
|
|
|
Set<String> uniqueOperationIds = new HashSet<>();
|
|
Set<String> nonUniqueOperationIds = new HashSet<>();
|
|
|
|
|
|
|
|
|
|
for (PathItem processedItem : validatedApi.getPaths().sequencedValues()) {
|
|
Stream.of(processedItem.getDelete(),
|
|
processedItem.getGet(),
|
|
processedItem.getPost(),
|
|
processedItem.getPut(),
|
|
processedItem.getPut(),
|
|
processedItem.getPatch(),
|
|
processedItem.getHead(),
|
|
processedItem.getOptions(),
|
|
processedItem.getTrace())
|
|
.filter(Objects::nonNull)
|
|
.forEach(
|
|
operation -> {
|
|
if (uniqueOperationIds.contains(operation.getOperationId())) {
|
|
validationResult.getErrors()
|
|
.add(
|
|
new Invalid(
|
|
ValidationRule.error("Non unique operationId", o -> null),
|
|
"Non unique operationId",
|
|
"Path: " + processedItem.get$ref() + " Operation:" + operation.getOperationId()));
|
|
nonUniqueOperationIds.add(operation.getOperationId());
|
|
uniqueOperationIds.add(operation.getOperationId());
|
|
} else {
|
|
uniqueOperationIds.add(operation.getOperationId());
|
|
}
|
|
}
|
|
);
|
|
|
|
}
|
|
|
|
|
|
if (validationResult.getErrors().isEmpty() && validationResult.getWarnings().isEmpty()) {
|
|
System.out.println("Validation complete. No validation errors or warning found. File is valid.");
|
|
} else {
|
|
System.out.println("Validation errors:");
|
|
validationResult.getErrors().forEach(System.out::println);
|
|
System.out.println("Validation warnings:");
|
|
validationResult.getWarnings().forEach(w -> System.out.println("Severity: " + w.getSeverity().name() + "\nRule: " + w.getRule().getDescription() + "\nMessage:\n" + w.getMessage() + "\nDetails:" + w.getDetails()));
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
}
|