Search code examples
javaannotationsmicronautmicronaut-client

How to map errorType using Micronaut client annotation


How to map errorType using Micronaut client annotation, In case of programatically we can provide body type and errorType objects in case of success and failure.

Programmatically calling client:

import io.micronaut.core.type.Argument;
import io.micronaut.http.HttpRequest;
import io.micronaut.http.HttpResponse;
import io.micronaut.http.MediaType;
import io.micronaut.http.client.DefaultHttpClient;
import io.micronaut.http.client.exceptions.HttpClientResponseException;
import io.micronaut.http.uri.UriBuilder;
import io.reactivex.Single;
import java.net.URL;

@Singleton
public class Test{
    public User getUser(String id) {
        try {
            String uriPath = UriBuilder.of("url")
                            .queryParam("id", id)
                            .toString();

        DefaultHttpClient httpClient = new DefaultHttpClient(new URL(""),httpClientConfiguration);

        Single<HttpResponse<User>> single = Single.fromPublisher(httpClient.exchange(
        HttpRequest.GET(uriPath).header(X_REQUEST_ID, REQUEST_ID).accept(MediaType.APPLICATION_JSON_TYPE),
        Argument.of(User.class), //bodyType
        Argument.of(Object.class) //errorType
        ));

        HttpResponse<User> response = single.blockingGet();
        User user = response.body();
        return user;            
        } catch (HttpClientResponseException | Exception e ) {              
        } 
    }
}

Calling Client using annotations

import io.micronaut.http.HttpResponse;
import io.micronaut.http.MediaType;
import io.micronaut.http.annotation.Consumes;
import io.micronaut.http.annotation.Get;
import io.micronaut.http.annotation.Header;
import io.micronaut.http.client.annotation.Client;
import io.reactivex.Single;
@Client(value = "url",
path = "/user")
public interface TestClient {
    @Get("?id=123")
    @Consumes(MediaType.APPLICATION_JSON)
        Single<HttpResponse<User>> getUser();
   }

Solution

  • If you want to define your own custom object as errorType, you can declare when using declarative client in micronaut as follows:

    @Client(id="",//The ID of the client
                value = "url", //The URL or service ID of the remote service
                path = "/user",//The base URI for the client. Only to be used in conjunction with id().
                errorType=YourCustomObject.class,//The type used to decode errors
                configuration=<? extends HttpClientConfiguration>//The http client configuration bean to use
                )
    public interface ExternalCallClient{
        //some API method
    }
    

    Then at your connector client class:

    class Connect{
    
    @Inject
    private ExternalCallClient externalCallClient;
    
    call(){
    
        try{
            //call to external API method using externalCallClient
          }catch(HttpClientResponseException e){
    
             Optional<YourCustomObject> error = e.getResponse()
                                                 .getBody(YourCustomObject.class)
                }
            }
        }
    

    Micronaut client throw a HttpClientResponseException for HTTP code(400 and above 400(except 404)) in case of exception from underlying client. So if the underlying client provides a custom error object in case of exception as a response body, this custom error type can be used for gracefully error handling and logging.

    Similar approach can be used for DefaultHttpClient too.