kamikat / moshi-jsonapi

JSON API v1.0 Specification in Moshi.
MIT License
156 stars 34 forks source link

Getting Error list from errorBody #44

Closed ericdsw closed 7 years ago

ericdsw commented 7 years ago

I'm currently using this library alongside with Retrofit, and I'm stuck on how to properly read my api's error list from the provided Document instance.

From what I understand, the Document class has the method errors() which should return a list of moe.banana.jsonapi2.Error instances, so I declared my MyAPI interface like this so i was able to access the Document on my callback directly:

interface MyAPI {
   @GET("foo")
   Call<Document<Foo>> getFoo();
}

I already registered the proper Converter.Factory instance to the Retrofit client and a success response correctly generates the expected Document<Foo> responseBody.

While a success response works, when my api returns an error object and a 4xx status code I no longer can access the parsed Document instance.

Take this example for instance: say I make a request to the myApi/foo endpoint and it generates the following output with a 401 Unauthorized status code:

{
  "errors": [
    {
      "title": "unauthorized",
      "detail": "You do not have permission to execute this request",
      "status": "401",
      "code": "2245"
    }
  ]
}

And I have this on my Retrofit instance callback:

@Override
public void onResponse(Call<Document<Foo>> call, Response<Document<Foo>> response) {
    if (response.isSuccessful()) {
        Foo foo = response.body().get();
        // Use the Foo instance, this part works
    } else {
        // Response's status was 4xx (error)
        List<Error> errors = response.body().errors();
    }
}

The call to List<Error> errors = response.body().errors() generates a NullPointerException because an unsuccessful request's body() method returns null and the errorBody() method is the one that contains the actual response data (however, errorBody() gives an instance of ResponseBody instead of a parsed instance).

My question is: How should I properly parse this kind of error, since an error response will no longer try to parse it to a Document instance? Should I make a custom JsonAdapter for an error response? If so, How should I implement it?

Any help would be appreciated.

kamikat commented 7 years ago

Retrofit only parses a successful (2xx) response with supplied converter. So when you get an error response from server you need to manually call:

moshi.adapter(Document.class).fromJson(response.errorBody().source())

to deserialize that into a Document object.

Here's a detailed introduction to error handling in Retrofit: https://futurestud.io/tutorials/retrofit-2-simple-error-handling