1
votes

There's a rest-route with multiple possible Rest-responces (They are of different types, but let's assume it's just MyResponse.class).

rest().post("/{{camel.rest.version}}/myjson")
        .consumes("application/json").produces("application/json")
        .type(SampleRequest.class)
        .responseMessage().code("200").responseModel(MyResponse.class).endResponseMessage()
        .responseMessage().code("400").responseModel(MyResponse.class).endResponseMessage()
        .responseMessage().code("500").responseModel(MyResponse.class).endResponseMessage()
        .route().routeId("rest_myroute")
        .log(LoggingLevel.INFO, "API_REQ Recieved http request ${body}")
        .process(sampleProcessor).id("sample_transform")
        .log(LoggingLevel.INFO, "API_RESP Response ${body}")
        .endRest();

The processor does some verification/business logic. Roughly it looks like:

@Override
public void process(Exchange exchange) throws Exception {
    SampleRequest inReq = exchange.getIn().getBody(SampleRequest.class);
    if (inReq.getMsgMode().equals("500"))
        exchange.getOut().setHeader(Exchange.HTTP_RESPONSE_CODE, HttpStatus.SC_INTERNAL_SERVER_ERROR);
    if (inReq.getMsgMode().equals("400"))
        exchange.getOut().setHeader(Exchange.HTTP_RESPONSE_CODE, HttpStatus.SC_BAD_REQUEST);
    MyResponse myClass = new MyResponse();
    myClass.setRecId("123456");
    exchange.getOut().setBody(myClass);
}

Execution result for positive case:

Code Details 200 Response body { "recId": "123456" }

500 or 400 case Code Details 400 Error: Bad Request Response headers connection: keep-alive

(no body)

If I change route to manual marshalling:

rest().post("/{{camel.rest.version}}/myjson")
        .consumes("application/json").produces("application/json")
        .type(SampleRequest.class)                
        .route().routeId("rest_myroute")
        .log(LoggingLevel.INFO, LoggingConst.API_REQ+" Recieved http request ${body}")
        .process(sampleProcessor).id("sample_transform")
        .marshal().json(JsonLibrary.Jackson)
        .log(LoggingLevel.INFO, LoggingConst.API_RESP+" Response ${body}")
        .endRest();

Results are the same.

Ok. Just in case using getOut() is not good, lets try getIn(). Processor using getIn()

@Override
public void process(Exchange exchange) throws Exception {
    SampleRequest inReq = exchange.getIn().getBody(SampleRequest.class);
    if (inReq.getMsgMode().equals("500"))
        exchange.getIn().setHeader(Exchange.HTTP_RESPONSE_CODE, HttpStatus.SC_INTERNAL_SERVER_ERROR);
    if (inReq.getMsgMode().equals("400"))
        exchange.getIn().setHeader(Exchange.HTTP_RESPONSE_CODE, HttpStatus.SC_BAD_REQUEST);
    MyResponse myClass = new MyResponse();
    myClass.setRecId("123456");
    exchange.getIn().setBody(myClass);
}

Results:

Positive case:

Code Details 200 Response body "eyJyZWNJZCI6IjEyMzQ1NiJ9"

(double marshalling was done)

Negative case:

400 Error: Bad Request Response body { "recId": "123456" }

Let's remove marshalling completly!

rest().post("/{{camel.rest.version}}/myjson")
        .consumes("application/json").produces("application/json")
        .type(SampleRequest.class)
        .route().routeId("rest_myroute")
        .log(LoggingLevel.INFO, LoggingConst.API_REQ+" Recieved http request ${body}")
        .process(sampleProcessor).id("sample_transform")/*.streamCaching()*/
        .log(LoggingLevel.INFO, LoggingConst.API_RESP+" Response ${body}")
        .endRest();

Positive result:

Code Details 200 Response body { "recId": "123456" }

Negative result:

Code Details 400 Error: Bad Request Response body can't parse JSON. Raw result:

class MyResponse { recId: 123456 }

(recieved raw data)

In all the cases my API-logs show the same result BEFORE camel prepares rest response:

{"timestamp":"2018-08-21T16:04:37.284+00:00","level":"INFO","logger_name":"rest_myroute","message":"ApiRq Recieved http request SampleRequest(msgMode=400)","traceId":"-4589659693669010018","spanId":"-3263510332551481190","camel.exchangeId":"ID-VRN26-1534867331800-0-3","camel.contextId":"IndividualClientService","camel.messageId":"ID-VRN26-1534867331800-0-4","camel.breadcrumbId":"ID-VRN26-1534867331800-0-3","camel.routeId":"rest_myroute","parentId":"-4589659693669010018"}
{"timestamp":"2018-08-21T16:04:37.288+00:00","level":"INFO","logger_name":"rest_myroute","message":"ApiRsp Response {\"recId\":\"123456\"}","traceId":"-4589659693669010018","spanId":"-3263510332551481190","camel.exchangeId":"ID-VRN26-1534867331800-0-3","camel.contextId":"IndividualClientService","camel.messageId":"ID-VRN26-1534867331800-0-4","camel.breadcrumbId":"ID-VRN26-1534867331800-0-3","camel.routeId":"rest_myroute","parentId":"-4589659693669010018"}

Camel version: 2.21.0.000033-fuse-000001-redhat-1

Is this a Camel-bug? If so, whas it fixed? Any workaround?

1

1 Answers

3
votes

Found a solution. Looks like Camel default route config prevents marshalling bodies if error occurred. Even if you manually declare that you need marshalling in .responseModel(MyClass.class)

Set up skipBindingOnErrorCode(false)

@Bean
    RouteBuilder restConfiguration(){

        RouteBuilder restConfiguration = new RouteBuilder() {
            @Override
            public void configure() throws Exception{

                restConfiguration().component("servlet")
                        .bindingMode(RestBindingMode.json)
                        .skipBindingOnErrorCode(false) //!!!!!!!!! add this
                        .contextPath(apiContextPath); 
            }
        };
        return restConfiguration;
    }