How can I use Retrofit2 to parse these two kinds of API responses?
Ok response (HTTP 200):
{
"data": {
"foo": "bar"
}
}
Error response (HTTP 200):
{
"error": {
"foo": "bar"
}
}
I've read tons of SO questions and tutorials, but I don't know how to do that, I've tried:
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapterFactory(new ItemTypeAdapterFactory());
Gson gson = gsonBuilder.create();
final Retrofit retrofit = new Retrofit.Builder()
.client(getOkHttpClient())
.baseUrl(Constants.API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
And this is my ItemTypeAdapterFactory:
class ItemTypeAdapterFactory implements TypeAdapterFactory {
public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> type) {
final TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type);
final TypeAdapter<JsonElement> elementAdapter = gson.getAdapter(JsonElement.class);
return new TypeAdapter<T>() {
public void write(JsonWriter out, T value) throws IOException {
delegate.write(out, value);
}
public T read(JsonReader in) throws IOException {
JsonElement jsonElement = elementAdapter.read(in);
if (jsonElement.isJsonObject()) {
JsonObject jsonObject = jsonElement.getAsJsonObject();
// Data key
if (jsonObject.has(Constants.JSON_KEY_DATA)) {
JsonElement jsonData = jsonObject.get(Constants.JSON_KEY_DATA);
// Primitive
if (jsonData.isJsonPrimitive()) {
jsonElement = jsonData.getAsJsonPrimitive();
}
// JSON object
else if (jsonData.isJsonObject()) {
jsonElement = jsonData;
}
// JSON object array
else if (jsonData.isJsonArray()) {
jsonElement = jsonData.getAsJsonArray();
}
}
}
return delegate.fromJsonTree(jsonElement);
}
}.nullSafe();
}
}
But now I don't know the type to be declared on retrofit2 interface, inside Call:
@GET("login")
Call<?> login(@Query(Constants.API_PARAM_TOKEN) String token);
Could you please point me in the right direction?
In a similar case, I once used JsonObject as type, so your function will look like this:
@GET("login")
Call<?> login(@Query(Constants.API_PARAM_TOKEN) String token);
Next, when you make a retrofit call, you keep the response as a string. So, in your java code, do something like this:
Call<JsonObject> call = RetrofitClient.getAPIService().login('YOUR_INPUT');
Data data = null;
Error error = null;
call.enqueue(new Callback<JsonObject>() {
@Override
public void onResponse(Call<JsonObject> call, Response<JsonObject> response) {
if(response.isSuccessfull()){
String jsonString = response.body().toString();
if(jsonString.contains("data:")){
data = new Gson().fromJson(jsonString,Data.class);
}else{
error = new Gson().fromJson(jsonString,Error.class);
}
}
}
Here, I have used Data and Error these 2 classes. They are the POJOs. So Data can look something like this:
Data.java:public class Data implements Serializable{
@SerializedName("foo")
@Expose
private Foo foo; // Foo is your desired data type
}
Same goes for Error. So depending on your rest of the code, make necessary changes. Good luck.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With