This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch fix/CAMEL-24114 in repository https://gitbox.apache.org/repos/asf/camel.git
commit 70370ac67210184674b1457c27d403d539c7b806 Author: Claus Ibsen <[email protected]> AuthorDate: Thu Jul 16 17:03:52 2026 +0200 CAMEL-24114: camel-rest-openapi - Request validator also checks exchange variables and endpoint literal parameters for required query parameters Signed-off-by: Claus Ibsen <[email protected]> Co-Authored-By: Claude Opus 4.6 <[email protected]> Signed-off-by: Claus Ibsen <[email protected]> --- .../rest/openapi/RestOpenApiEndpoint.java | 1 + .../openapi/validator/DefaultRequestValidator.java | 19 +++++++++-- .../openapi/RestOpenApiRequestValidationTest.java | 39 ++++++++++++++++++++++ 3 files changed, 56 insertions(+), 3 deletions(-) diff --git a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpoint.java b/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpoint.java index 761ca925126c..47abaac46f37 100644 --- a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpoint.java +++ b/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpoint.java @@ -864,6 +864,7 @@ public final class RestOpenApiEndpoint extends DefaultEndpoint { OpenAPI openAPI, Operation operation, String method, String uriTemplate) { DefaultRequestValidator answer = new DefaultRequestValidator(); answer.setOperation(new RestOpenApiOperation(operation, method, uriTemplate)); + answer.setEndpointParameters(parameters); return answer; } diff --git a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/validator/DefaultRequestValidator.java b/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/validator/DefaultRequestValidator.java index af20dc487bf4..112b951da96d 100644 --- a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/validator/DefaultRequestValidator.java +++ b/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/validator/DefaultRequestValidator.java @@ -18,6 +18,7 @@ package org.apache.camel.component.rest.openapi.validator; import java.util.Collections; import java.util.LinkedHashSet; +import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; @@ -34,12 +35,17 @@ import static org.apache.camel.support.http.RestUtil.isValidOrAcceptedContentTyp public class DefaultRequestValidator implements RequestValidator { private RestOpenApiOperation operation; + private Map<String, Object> endpointParameters = Collections.emptyMap(); @Override public void setOperation(RestOpenApiOperation operation) { this.operation = operation; } + public void setEndpointParameters(Map<String, Object> endpointParameters) { + this.endpointParameters = endpointParameters != null ? endpointParameters : Collections.emptyMap(); + } + @Override public RestOpenApiOperation getOperation() { return operation; @@ -100,9 +106,16 @@ public class DefaultRequestValidator implements RequestValidator { .stream() .filter(parameter -> Objects.nonNull(parameter.getRequired()) && parameter.getRequired()) .forEach(parameter -> { - Object header = message.getHeader(parameter.getName()); - if (ObjectHelper.isEmpty(header)) { - validationErrors.add("Query parameter '" + parameter.getName() + "' is required but none found."); + String name = parameter.getName(); + Object value = message.getHeader(name); + if (ObjectHelper.isEmpty(value)) { + value = exchange.getVariable(name); + } + if (ObjectHelper.isEmpty(value)) { + value = endpointParameters.get(name); + } + if (ObjectHelper.isEmpty(value)) { + validationErrors.add("Query parameter '" + name + "' is required but none found."); } }); diff --git a/components/camel-rest-openapi/src/test/java/org/apache/camel/component/rest/openapi/RestOpenApiRequestValidationTest.java b/components/camel-rest-openapi/src/test/java/org/apache/camel/component/rest/openapi/RestOpenApiRequestValidationTest.java index 158ecea5c4c8..3a4a2b951c79 100644 --- a/components/camel-rest-openapi/src/test/java/org/apache/camel/component/rest/openapi/RestOpenApiRequestValidationTest.java +++ b/components/camel-rest-openapi/src/test/java/org/apache/camel/component/rest/openapi/RestOpenApiRequestValidationTest.java @@ -307,6 +307,37 @@ public class RestOpenApiRequestValidationTest extends CamelTestSupport { assertFalse(pets.isEmpty()); } + @ParameterizedTest + @MethodSource("petStoreVersions") + @SuppressWarnings("unchecked") + void requestValidationWithRequiredQueryParameterFromEndpointUri(String petStoreVersion) { + Map<String, Object> headers = Map.of("petStoreVersion", petStoreVersion); + List<Pet> pets + = template.requestBodyAndHeaders("direct:validateQueryParamsFromEndpoint", null, headers, List.class); + assertFalse(pets.isEmpty()); + } + + @ParameterizedTest + @MethodSource("petStoreVersions") + @SuppressWarnings("unchecked") + void requestValidationWithRequiredQueryParameterFromVariable(String petStoreVersion) { + Exchange exchange = template.request("direct:validateQueryParamsFromVariable", new Processor() { + @Override + public void process(Exchange exchange) throws Exception { + exchange.getMessage().setHeader("petStoreVersion", petStoreVersion); + exchange.setVariable("status", "available"); + } + }); + + Exception exception = exchange.getException(); + if (exception != null) { + throw new AssertionError("Unexpected validation failure", exception); + } + List<Pet> pets = exchange.getMessage().getBody(List.class); + assertNotNull(pets); + assertFalse(pets.isEmpty()); + } + @ParameterizedTest @ValueSource(strings = { "petStoreV3" }) void requestValidationWithBinaryBody(String petStoreVersion) throws IOException { @@ -460,6 +491,14 @@ public class RestOpenApiRequestValidationTest extends CamelTestSupport { .toD("${header.petStoreVersion}:findPetsByStatus?requestValidationEnabled=true") .unmarshal(jacksonDataFormat); + from("direct:validateQueryParamsFromEndpoint") + .toD("${header.petStoreVersion}:findPetsByStatus?requestValidationEnabled=true&status=available") + .unmarshal(jacksonDataFormat); + + from("direct:validateQueryParamsFromVariable") + .toD("${header.petStoreVersion}:findPetsByStatus?requestValidationEnabled=true") + .unmarshal(jacksonDataFormat); + from("direct:binaryContent") .toD("${header.petStoreVersion}:uploadFile?requestValidationEnabled=true&produces=application/octet-stream") .unmarshal(jacksonDataFormat);
