Search code examples
javagroovymicronautmicronaut-clientmicronaut-rest

exceptionOnErrorStatus in ClientConfiguration of Declarative Client not being applied in Micronaut version 3.7.3


I have provided a configuration class to my Declarative HttpClient, to force throwing an exception on error (status>400), or maybe I misunderstood the exceptionOnErrorStatus configuration option.

@Client(value = "/", configuration = ApiClientConfiguration)
interface Api {
    @Get("/author/{id}")
    AuthorResource getAuthor(Long id, @Header(name="Authorization") String authorization)
}

Here's the configuration class

@ConfigurationProperties("httpclient.api")
class ApiClientConfiguration extends DefaultHttpClientConfiguration {
    @Override
    boolean isExceptionOnErrorStatus() {
        return true
    }
}

My @MicronautTest is expected to throw an exception, but it doesn't:

    def "It fails to get an non-existing Author"() {
        given:
        def token = viewer()

        when:
        //This commented code throws an exception as expected
/*
        def author = client.toBlocking().exchange(HttpRequest.create(
                HttpMethod.GET,
                "/author/${badId}"
        ).bearerAuth(token))
*/
        //This does not despite the provided HttpClientConfiguration
        def author = api.getAuthor(badId, bearerAuth(token))

        then:
        def ex = thrown(HttpClientResponseException)
        ex.status == NOT_FOUND
        ex.getResponse().getBody(ErrorResource).map {
            assert it.message == "Author with id ${badId} not found."
            it
        }.isPresent()

        where:
        badId = anyInt()
    }

Any help appreciated. I am not used to configuration classes, so there may be a mistake in how I use it, the other possibility is that exceptionOnErrorStatus does not mean what I think it means. I have checked the documentation and I think it does, though.


Solution

  • It looks like the Configuration class is used, the method isExceptionOnErrorStatus() is called, but it is not interpreted as I thought it would.

    Conclusion, when you are using a Declarative client and want to test the response when the status>400, make your interface return a HttpResponse<X>.

        @Get("/author/{id}")
        HttpResponse<AuthorResource> getAuthor(Long id, @Header(name = "Authorization") String authorization)
    

    The behaviour is different from the low-level client, which throws an exception.

    Modify your Test:

            def response = api.getAuthor(badId, bearerAuth(token))
            response.status == NOT_FOUND
            response.getBody(ErrorResponse).map {
                assert it.message == "Author with id ${badId} not found."
                it
            }.isPresent()