apache / camel-quarkus

Apache Camel Quarkus
https://camel.apache.org
Apache License 2.0
257 stars 191 forks source link

JsonParseException not caught when using OpenAPI generated REST DSL #3155

Closed nadworny closed 1 year ago

nadworny commented 3 years ago

Description

I'm using an Camel REST DSL generator for my service. The generated class looks the following:

public final class GeneratedRoute extends RouteBuilder {
    /**
     * Defines Apache Camel routes using REST DSL fluent API.
     */
    public void configure() {

        rest()
                .post("/test")
                .id("test")
                .produces("application/json")
                .param()
                .name("body")
                .type(RestParamType.body)
                .required(true)
                .endParam()
                .to("direct:test");

    }
}

Now, I would like to handle the exception thrown by this endpoint when I send an invalid JSON request.

Expected behaviour

The exception processor is catching it and returning a custom error response.

Actual behaviour

A 500 is returned without going through the processor with the following stacktrace. Maybe that's a generic camel and RouteBuilder problem that I can't catch exceptions that are created in a different class like the one which is generated?

How to reproduce

Add the above GeneratedRoute to the rest example project

Add this ErrorResponse (or any pojo) which is generated also from the OpenAPI to the example project: https://gist.github.com/nadworny/4f391b2eeab28e94b3b297c1dd174d8c

Add this class to the Routes.java

@ApplicationScoped
class ErrorResultProcessor implements Processor {

    @Override
    public void process(Exchange exchange) {
        var error = new ErrorResponse();
        error.setStatus(HTTP_BAD_REQUEST);
        exchange.getMessage().setBody(error);
    }

}

Add the following code to the configure() method in Routes.java

        onException(Exception.class)
            .handled(true)
            .log(ERROR, "${exception.message}")
            .process(errorResultProcessor)
            .marshal()
            .json();

        restConfiguration().bindingMode(RestBindingMode.json);

        from("direct:test")
            .process(p -> {
                p.getIn().setBody(new Fruit("test", "test"));
            });

Send an invalid request:

curl --location --request POST 'localhost:8080/test' \
--header 'Content-Type: application/json' \
--data-raw '{
    "name": "test"xxx
}'

Environment

openjdk version "11.0.11" 2021-04-20 macos 11.6 (20G165) https://github.com/apache/camel-quarkus-examples version: b1352cd4c0d2a1b7b17ba73c3aca410f516d42f3

jamesnetherton commented 3 years ago

I think the problem is that in your onException handler you are doing:

.marshal().json();

Since the JSON RestBindingMode is enabled, you don't need to do the marshalling step manually. It will result in Camel attempting to marshal an already marshalled body. Hence the 500 response.

nadworny commented 3 years ago

Thanks for the suggestion @jamesnetherton . Unfortunately after applying it, nothing changed. Probably I forgot to mention but once the GeneratedRoute is within the same configure as the onException, everything works as expected.

davsclaus commented 3 years ago

That is expected as the 2 route builders are not sharing onException.

In Camel 3.12 onwards you can use route configurations to share error handling to all route builder classes https://camel.apache.org/manual/route-configuration.html