Init commit

This commit is contained in:
Artur Kruszewski
2026-05-17 21:24:07 +02:00
commit 2e71707b79
14 changed files with 923 additions and 0 deletions
@@ -0,0 +1,40 @@
package com.krusoe.openapimerge.validate;
import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.PathItem;
import org.openapitools.codegen.validation.GenericValidator;
import org.openapitools.codegen.validation.Severity;
import org.openapitools.codegen.validation.ValidationResult;
import org.openapitools.codegen.validation.ValidationRule;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class UniqueOperationIdValidator extends GenericValidator<PathItem> {
private static Set<String> uniqueOperationIds = new HashSet<>();
public UniqueOperationIdValidator() {
super(List.of(ValidationRule.create(Severity.ERROR,
"OperationId should be unique across the whole file, all paths and methods", "OperationId is not unique", UniqueOperationIdValidator::testForUniqueness)));
}
static ValidationRule.Result testForUniqueness(Object item) {
if (item instanceof PathItem) {
ValidationResult result = new ValidationResult();
for (Operation operation : ((PathItem) item).readOperations()) {
if (uniqueOperationIds.contains(operation.getOperationId())) {
return new ValidationRule.Fail("Operation is not unique. OperationId: %s Path: %s".formatted(operation.getOperationId(), ((PathItem) item).get$ref()));
} else {
uniqueOperationIds.add(operation.getOperationId());
}
}
return new ValidationRule.Pass();
}
throw new IllegalArgumentException();
}
}
@@ -0,0 +1,60 @@
package com.krusoe.openapimerge.validate;
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 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;
@Command
public class ValidateCommand {
private ObjectMapper objectMapper = new ObjectMapper();
@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);
var uniqValidator = new UniqueOperationIdValidator();
validatedApi.getPaths().sequencedValues().forEach(uniqValidator::validate);
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()));
}
}
}
}