Android Retrofit Parameterized @Headers

I am using OAuth and I need to put the OAuth token in my header every time I make a request. I see the @Header annotation, but is there a way to make it parameterized so i can pass in at run time?

Here is the concept

@Header({Authorization:'OAuth {var}', api_version={var} })

Can you pass them in at Runtime?

@GET("/users")
void getUsers(
    @Header("Authorization") String auth, 
    @Header("X-Api-Version") String version, 
    Callback<User> callback
)

Solution 1:

Besides using @Header parameter, I'd rather use RequestInterceptor to update all your request without changing your interface. Using something like:

RestAdapter.Builder builder = new RestAdapter.Builder()
    .setRequestInterceptor(new RequestInterceptor() {
        @Override
        public void intercept(RequestFacade request) {
            request.addHeader("Accept", "application/json;versions=1");
            if (isUserLoggedIn()) {
                request.addHeader("Authorization", getToken());
            }                    
        }
    });

p/s : If you are using Retrofit2, you should use Interceptor instead of RequestInterceptor

Since RequestInterceptor is not longer available in Retrofit 2.0

Solution 2:

Yes, you can pass them in runtime. As a matter of fact, pretty much exactly as you typed it out. This would be in your API interface class, named say SecretApiInterface.java

public interface SecretApiInterface {

    @GET("/secret_things")
    SecretThing.List getSecretThings(@Header("Authorization") String token)

}

Then you pass the parameters to this interface from your request, something along those lines: (this file would be for example SecretThingRequest.java)

public class SecretThingRequest extends RetrofitSpiceRequest<SecretThing.List, SecretApiInteface>{

    private String token;

    public SecretThingRequest(String token) {
        super(SecretThing.List.class, SecretApiInterface.class);
        this.token = token;
    }

    @Override
    public SecretThing.List loadDataFromNetwork() {
        SecretApiInterface service = getService();
        return service.getSecretThings(Somehow.Magically.getToken());
    }
}

Where Somehow.Magically.getToken() is a method call that returns a token, it is up to you where and how you define it.

You can of course have more than one @Header("Blah") String blah annotations in the interface implementation, as in your case!

I found it confusing too, the documentation clearly says it replaces the header, but it DOESN'T!
It is in fact added as with @Headers("hardcoded_string_of_liited_use") annotation

Hope this helps ;)

Solution 3:

The accepted answer is for an older version of Retrofit. For future viewers the way to do this with Retrofit 2.0 is using a custom OkHttp client:

OkHttpClient httpClient = new OkHttpClient.Builder()
  .addInterceptor(new Interceptor() {
    @Override
    public Response intercept(Chain chain) throws IOException {
      Builder ongoing = chain.request().newBuilder();
      ongoing.addHeader("Accept", "application/json;versions=1");
      if (isUserLoggedIn()) {
        ongoing.addHeader("Authorization", getToken());
      }
      return chain.proceed(ongoing.build());
    }
  })
  .build();

Retrofit retrofit = new Retrofit.Builder()
  // ... extra config
  .client(httpClient)
  .build();

Hope it helps someone. :)

Solution 4:

Retrofit 2.3.0

OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder();
    okHttpClientBuilder
            .addInterceptor(new Interceptor() {
                @Override
                public okhttp3.Response intercept(Chain chain) throws IOException {
                    Request request = chain.request();
                    Request.Builder newRequest = request.newBuilder().header("Authorization", accessToken);
                    return chain.proceed(newRequest.build());
                }
            });

    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(GithubService.BASE_URL)
            .client(okHttpClientBuilder.build())
            .addConverterFactory(GsonConverterFactory.create())
            .build();

I am using this to connect to GitHub.