In fact as you work with creating a new API Call. The problem with dealing with server errors and API errors is often the same and repeats each time you create. Repeated processing of a task can lead to errors, boilerplate …
To solve this problem, today we will together clean API calls and recreate the model to receive data from the server returned.
In this article I will clean the Retrofit API call. A library most widely used in Android when handling requests to the server. Also use generic to rewrite the model that received data from the returned server.
A typical API Call often:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | public void requestRandomDogImage(final NetworkResponseListener<BreedRandomImage> listener, DogAPI api) { api.requestRandomDogImage().call.enqueue(new Callback<BreedRandomImage>() { @Override public void onResponse(@NonNull Call<BreedRandomImage> call, @NonNull Response<BreedRandomImage> response) { if (listener != null) { listener.onResponseReceived(response.body()); } } @Override public void onFailure(@NonNull Call<BreedRandomImage> call, @NonNull Throwable t) { if (listener != null) { listener.onError(); } } }); } |
1 2 3 4 5 6 7 | public interface NetworkResponseListener<Response> { void onResponseReceived(Response response); void onError(); } |
Each API call Retrofit when called will return us a Callback<T>
object. T here is the generic type is the object containing the data that we receive when the request is completed.
1 2 3 4 5 6 7 | public interface Callback<T> { void onResponse(Call<T> call, Response<T> response); void onFailure(Call<T> call, Throwable t); } |
1 2 3 4 5 6 7 8 9 | public interface Call<T> extends Cloneable { void enqueue(Callback<T> callback); Response<T> execute() throws IOException; ... } |
As you can see in the code above Callback<T>
is an interface that will be passed into each API Call
Now, instead of using the original Callback provided by Retrofit, we will rewrite by inheriting it, refactor into the same callback we want.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | public abstract class SimpleCallback<T> implements Callback<T> { public abstract void onSuccess(T respone); public abstract void onError(String message); @Override public void onResponse(Call<T> call, Response<T> response) { if (response.isSuccessful() && response.body() != null) { onSuccess(response.body()); } else { onError(response.message()); } } @Override public void onFailure(Call<T> call, Throwable t) { onError(t.getMessage()); } } |
So, if we need a request now, we will use SimpleCallback<T>
instead of Callback<T>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | public void requestRandomDogImage(final NetworkResponseListener<BreedRandomImage> listener, DogAPI api) { api.requestRandomDogImage().enqueue(new SimpleCallback<BreedRandomImage>() { @Override public void onSuccess(BreedRandomImage respone) { } @Override public void onError(String message) { } }); } |
Recently we have rewritten Callback<T>
. Now we will continue to rewrite the model for our received data.
Normally when the respone returned from the server the error object will be the same, and the data object returned will vary depending on each request. Recognizing this we will use the generic type to rewrite the model.
Status: common to all respones
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | public class Status { private String error; private String message; public String getError() { return error; } public void setError(String error) { this.error = error; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } } |
Respone class will receive data depending on each request so we will use the generic type here:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | package com.example.cleanapi; public class Respone<T> { private T data; private Status status; public T getData() { return data; } public void setData(T data) { this.data = data; } public Status getStatus() { return status; } public void setStatus(Status status) { this.status = status; } } |
After combining both SimpleCallback<T>
and Respone<T>
, our request will now become as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | public void requestRandomDogImage(final NetworkResponseListener<BreedRandomImage> listener, DogAPI api) { api.requestRandomDogImage().enqueue(new SimpleCallback<Respone<BreedRandomImage>>() { @Override public void onSuccess(Respone<BreedRandomImage> respone) { } @Override public void onError(String message) { } }); } |
So just now I showed how to clean API Retrofit in Android:
- re-implement
Callback<T>
- Rewrite the model to receive data.
Happy coding!
The article is available at: https://android.jlelse.eu/clean-your-api-calls-79d67098d258