简体   繁体   中英

How to consume Retrofit response with possible response types?

I am introducing Retrofit 2 to one of our new projects. I am having a particular issue when I consume a web service response using Retrofit.

I am using retrofit 2.3.0, and the retrofit gson converter 2.3.0.

My problem is as follows. The web service API that I am consuming will respond with 2 possible Response Models when a request is 200-OK.

  1. Web service handled request fine and responds with expected response model defined in response callback.
  2. Web service fails to handle request and sends back an exception model as the response. Still sending a 200-OK...

Believe me, I know the problem here... The web service should not be responding on success if a web service exception was thrown... it should be responding with a 500-5xx. All of this would become much easier. Anyways, I need to conform to this logic.

This is what I have and it is working however, I think there is a better approach to this and I don't want to write the same code over and over which performs the casts operations every time I consume a response. However, I am not sure which is the correct approach here.

call.enqueue(new Callback<JsonObject>() {

     @Override
     public void onResponse(Call<JsonObject> call, Response<JsonObject> response) {
        //cast operation
        Gson gson = new Gson();
        ServiceException exception = gson.fromJson(response.body(), ServiceException.class);
        if(response.isSuccessful()){
             if(null != exception.getCode()){
                 //handleException(exception);
             }else{
                 //User authenticated successfully.

                 //cast operation
                 LoginResponseModel loginResponseModel = gson.fromJson(response.body(), LoginResponseModel.class);
                 //Perform actions with login response model.

                 //Launch dashboard if everything is ok.
                 Intent startDashboard = new Intent(LoginActivity.this, DashboardActivity.class);
                 startActivity(startDashboard);
             }
         }
     }

     @Override
     public void onFailure(Call<JsonObject> call, Throwable t) {
         Log.e(TAG, t.getMessage());
     }

});

This is my desired goal:

call.enqueue(new Callback<LoginResponseModel, ServiceException>() {

        @Override
        public void onResponse(Call<LoginResponseModel, ServiceException> call, Response<LoginResponseModel, ServiceException> response) {
               if(response instanceof ServiceException){
                   handleException(response);
               }else if(response instanceof LoginResponseModel){
                   //User authenticated successfully.
                   LoginResponseModel loginResponseModel = gson.fromJson(response.body(), LoginResponseModel.class);
                   //Perform actions with login response model.

                   //Launch dashboard if everything is ok.
                   Intent startDashboard = new Intent(LoginActivity.this, DashboardActivity.class);
                   startActivity(startDashboard);

                }
            }
        }

        @Override
        public void onFailure(Call<LoginResponseModel, ServiceException> call, Throwable t) {
            Log.e(TAG, t.getMessage());
        }

    });

Do I need a custom Callback implementation to achieve my goal? Do I need a custom response interceptor? Do I need a custom response converter? Any ideas of a better approach?

I am a little new to Retrofit and I haven't found much information about a scenario like this.

Hm what about use try catch and handle gson JsonSyntaxException ? Something like this:

call.enqueue(new Callback<JsonObject>() {
        @Override
        public void onResponse(Call<JsonObject> call, Response<JsonObject> response) {
            Gson gson = new Gson();
            try {
                ServiceException exception = gson.fromJson(response.body(), ServiceException.class);
                //handleException(exception);
            } catch (JsonSyntaxException e) {
                // Incorrect class, deserialize using LoginResponseModel 
                LoginResponseModel loginResponseModel = gson.fromJson(response.body(), LoginResponseModel.class);
                //User authenticated successfully.
                //Launch dashboard if everything is ok.
                Intent startDashboard = new Intent(LoginActivity.this, DashboardActivity.class);
                startActivity(startDashboard);
            }
        }

        @Override
        public void onFailure(Call<JsonObject> call, Throwable t) {
            Log.e(TAG, t.getMessage());
        }
    });

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM