Skip to content
Advertisement

Request validation doesn’t happen in camel rest

I am trying to experiment by building some simple API’s with apache camel. The request body for a post request is empty but camel doesn’t return bad request instead it returns 201.

Here is what I do;

  1. Generate classes from studentreg-api.yaml [This is a valid openapi 3 yaml document]
  2. Using camel, spring boot to build REST endpoints Step
  3. Configured camel rest endpoint with clientRequestValidation(true)
  4. Start the server
  5. Open /api-docs and validated if the mandatory attributes are marked appropriately
  6. From postman made request to the POST endpoint with blank request body

Expected: 400 – Bad request Actual: 201

I couldn’t figure out what is that I am missing.

BaseRouteConfig.java

@ComponentScan
@Configuration
public class BaseRouteConfig extends RouteBuilder {

@Autowired
private Environment environment;

@Value("${studentregistration.api.path}")
private String basePath;


@Bean
ServletRegistrationBean servletRegistrationBean() {
    ServletRegistrationBean servlet = new ServletRegistrationBean(new CamelHttpTransportServlet(), basePath + "/*");
    servlet.setName("CamelServlet");
    return servlet;
}

@Override
public void configure() throws Exception {
    restConfiguration().component("servlet")
            .bindingMode(RestBindingMode.json)
            .dataFormatProperty("pretty-print", "true")
            .enableCORS(true)
            .port(environment.getProperty("server.port", "8085"))
            .contextPath(basePath)
            .apiContextPath("/api-docs")
            .apiVendorExtension(true)
            .apiProperty("api.title", "Student registration")
            .apiProperty("api.version", "0.1")
            .apiProperty("cors", "true")
            .clientRequestValidation(true);
    }
}

RegisterStudentRoute.java

@Component
public class RegisterStudentRoute extends RouteBuilder {

@Override
    public void configure() throws Exception {
        rest("/api/").consumes(MediaType.APPLICATION_JSON_VALUE)
                .produces(MediaType.APPLICATION_JSON_VALUE)
                .post("/registration")
                .type(RegisterStudentRequest.class)
                .clientRequestValidation(true)
                .outType(RegisterStudentResponse.class)
                .responseMessage().code(HttpStatus.CREATED.value())
                .endResponseMessage()
                .route().routeId("create-student-registration")
                .setHeader(Exchange.HTTP_RESPONSE_CODE, simple("201"))
                .to("log:success")
                .end().endRest();
    }
}

pom.xml

    <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.0</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>camel-rest</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>camel-rest</name>
    <description>Demo project for Spring Boot &amp; camel rest</description>
    <properties>
        <java.version>16</java.version>
        <camel.version>3.10.0</camel.version>
        <openapi-generator.version>5.1.0</openapi-generator.version>
        <springfox.version>2.9.2</springfox.version>
        <jackson-databind.version>0.2.1</jackson-databind.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.apache.camel.springboot</groupId>
            <artifactId>camel-servlet-starter</artifactId>
            <version>3.9.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.camel.springboot</groupId>
            <artifactId>camel-jackson-starter</artifactId>
            <version>3.9.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.camel.springboot</groupId>
            <artifactId>camel-openapi-java-starter</artifactId>
            <version>3.9.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.camel.springboot</groupId>
            <artifactId>camel-spring-boot-starter</artifactId>
            <version>3.9.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.camel.springboot</groupId>
            <artifactId>camel-http-starter</artifactId>
            <version>3.9.0</version>
        </dependency>
        <dependency>
            <groupId>org.openapitools</groupId>
            <artifactId>openapi-generator</artifactId>
            <version>${openapi-generator.version}</version>
        </dependency>
        <dependency>
            <groupId>org.openapitools</groupId>
            <artifactId>jackson-databind-nullable</artifactId>
            <version>${jackson-databind.version}</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>${springfox.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.4.5</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.openapitools</groupId>
                <artifactId>openapi-generator-maven-plugin</artifactId>
                <!-- RELEASE_VERSION -->
                <version>5.1.0</version>
                <!-- /RELEASE_VERSION -->
                <executions>
                    <execution>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                        <configuration>
                            <inputSpec>${project.basedir}/src/main/resources/api.yaml</inputSpec>
                            <generatorName>spring</generatorName>
                            <apiPackage>com.sample.camel-rest.api</apiPackage>
                            <modelPackage>com.sample.camel-rest.model</modelPackage>

                            <supportingFilesToGenerate>
                                ApiUtil.java
                            </supportingFilesToGenerate>
                            <configOptions>
                                <delegatePattern>true</delegatePattern>
                                <outputDir>${project.basedir}/generated</outputDir>
                            </configOptions>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

Advertisement

Answer

ok! I have figured out a simpler way to handle validation. Adding a route to bean-validator solved the problem! If we need to build custom error messages or if you need to build error model based on failures, you can use camel processor and javax.validator.

RegisterStudentRoute.java

@Component
public class RegisterStudentRoute extends RouteBuilder {

    @Autowired
    RegisterStudentRequestValidator registerStudentRequestValidator;

    @Override
    public void configure() throws Exception {
        rest("/api/").consumes(MediaType.APPLICATION_JSON_VALUE)
                .produces(MediaType.APPLICATION_JSON_VALUE)
                .post("/registration")
                .type(RegisterStudentRequest.class)
                .clientRequestValidation(true)
                .param().name("request-id").dataType("string")
                .type(RestParamType.header).required(true)
                .endParam()
                .outType(RegisterStudentResponse.class)
                .responseMessage().code(HttpStatus.CREATED.value())
                .endResponseMessage()
                .route().routeId("create-student-registration")
//                .process(registerStudentRequestValidator)
                .to("direct:validateReq")
                .setHeader(Exchange.HTTP_RESPONSE_CODE, simple("201"))
                .to("log:success")
                .end().endRest();

        from("direct:validateReq")
                .to("bean-validator://x")
                .to("mock:end");
    }
User contributions licensed under: CC BY-SA
1 People found this is helpful
Advertisement