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;
- Generate classes from studentreg-api.yaml [This is a valid openapi 3 yaml document]
- Using camel, spring boot to build REST endpoints Step
- Configured camel rest endpoint with
clientRequestValidation(true)
- Start the server
- Open /api-docs and validated if the mandatory attributes are marked appropriately
- 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 & 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"); }