Retrofit API declaration and inheritance

Retrofit 2.7 introduced Interface inheritance. This is great if you want to separate your API definition from the actual networking implementation. You can now define a “plain” interface as API contract, we’ll call this FooApi, and then have another (Retrofit specific) interface inherit from it and add all the Retrofit sugar.

There seems to be a small catch though to make this fully work. You need to make sure that your concrete Retrofit API does not get obfuscated. If it does, Retrofit will throw the following runtime exception: java.lang.IllegalArgumentException: HTTP method annotation is required (e.g., @GET, @POST, etc.).

Let’s say we created this concrete API declaration and called it FooRetrofitApi. We’ve also wired up all Retrofit annotations so it is able to make requests to your API.

All that is left to do is to exclude your concrete API from obfuscation. Do so by adding the following to your ProGuard rules:

-keep class nl.ansuz.FooRetrofitApi { *; }

Bob’s your uncle!


So why do the Retrofit annotations get stripped? I think that is because of the way the code is structured. If you follow clean code principles, you’ll end up referencing the FooApi throughout your project. The concrete FooRetrofitApi is only injected. As a result R8 might think that FooRetrofitApi can be more optimised than is actually the case.