Is there a way to add query parameter to every request with Retrofit 2?

JavaAndroidRetrofit

Java Problem Overview


I need to add a query parameter to every request made by Retrofit 2.0.0-beta2 library. I found this solution for Retrofit 1.9, but how to add RequestInterceptor in newest library version?

My interface:

@GET("user/{id}")
Call<User> getUser(@Path("id")long id);

@GET("users/")
Call<List<User>> getUser();

Client:

Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl(BASE_URL)
                    .addConverterFactory(GsonConverterFactory.create())
                    .client(CLIENT)  // custom OkHTTP Client
                    .build();
service = retrofit.create(userService.class);

Java Solutions


Solution 1 - Java

For the sake of completeness, here is the full code you need to add a parameter to every Retrofit 2.x request using a OkHttp-Interceptor:

OkHttpClient client = new OkHttpClient();

client.interceptors().add(new Interceptor() {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        HttpUrl url = request.url().newBuilder().addQueryParameter("name","value").build();
        request = request.newBuilder().url(url).build();
        return chain.proceed(request);
    }
});

Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("...")
        .client(client)
        .build();

Solution 2 - Java

now the Retrofit has release 2.0.0 and this is my solution:

OkHttpClient client = new OkHttpClient.Builder()
        .addInterceptor(new Interceptor() {
            @Override
            public Response intercept(Chain chain) throws IOException {

                String uid = "0";
                long timestamp = (int) (Calendar.getInstance().getTimeInMillis() / 1000);
                String signature = MD5Util.crypt(timestamp + "" + uid + MD5_SIGN);
                String base64encode = signature + ":" + timestamp + ":" + uid;
                base64encode = Base64.encodeToString(base64encode.getBytes(), Base64.NO_WRAP | Base64.URL_SAFE);

                Request request = chain.request();
                HttpUrl url = request.url()
                        .newBuilder()
                        .addQueryParameter("pageSize", "2")
                        .addQueryParameter("method", "getAliasList")
                        .build();

                request = request
                        .newBuilder()
                        .addHeader("Authorization", "zui " + base64encode)
                        .addHeader("from_client", "ZuiDeer")
                        .url(url)
                        .build();

                Response response = chain.proceed(request);
                return response;
            }
        }).build();


Retrofit retrofit = new Retrofit.Builder()
        .baseUrl(ApiConstants.API_BASE_URL)
        .client(client)
        .addConverterFactory(GsonConverterFactory.create())
        .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
        .build();

mRestfulService = retrofit.create(RestfulService.class);

Solution 3 - Java

In 3.2.0 and higher you should use addInterceptor() in OkHttpClient.Builder instead.

For example, with Retrolambda:

HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor()
        .setLevel(HttpLoggingInterceptor.Level.BASIC);

Interceptor clientInterceptor = chain -> {
    Request request = chain.request();
    HttpUrl url = request.url().newBuilder().addQueryParameter("name", "value").build();
    request = request.newBuilder().url(url).build();
    return chain.proceed(request);
};

OkHttpClient client = new OkHttpClient.Builder()
        .addNetworkInterceptor(clientInterceptor)
        .addInterceptor(loggingInterceptor)
        .build();

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

Solution 4 - Java

You have to switch to an Interceptor from OkHttp. Create an OkHttpClient, add the Interceptor to it an pass that client in the Retrofit Builder.

OkHttpClient client = new OkHttpClient();
client.interceptors().add(new Interceptor() {
    @Override
    public Response intercept(Chain chain) throws IOException {
        ...
    }
});

Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("...")
        .client(client)
        .build();

You can then adjust the request to your needs using chain.request().newBuilder(). See the documentation for details.

Solution 5 - Java

In kotlin, add the following interceptor to the OkHttpClient you set in Retrofit builder :

Retrofit.Builder()
    .baseUrl("...")
    .client(
        OkHttpClient.Builder()
            .addInterceptor { chain ->
                val url = chain
                    .request()
                    .url()
                    .newBuilder()
                    .addQueryParameter("key", "value")
                    .build()
                chain.proceed(chain.request().newBuilder().url(url).build())
            }
            .build()
    )
    .build()
    .create(FooService::class.java)

And, of course, extracting the OkHttpClient building into a val or an injection dependency would make it even more modular and lisible.

Solution 6 - Java

A lot of these answers are similar, but an issue I came accross is the chaining of functions inside the Interceptor which led it to fail for me. Changes cannot be made directly to a url according to the linked video. Rather, a copy of the url must be made and then reassigned back to the original url as shown below:

{

public method(){
    final String api_key = "key";

    OkHttpClient client = new OkHttpClient.Builder()
                          .addInterceptor(new Interceptor() {
                              @Override
                              public Response intercept(Chain chain) throws IOException {
                                    Request original = chain.request();
                                    HttpUrl httpUrl = original.url();

                                    HttpUrl newHttpUrl = httpUrl
                                                        .newBuilder()
                                                        .addQueryParameter("api_key", api_key)
                                                        .build();

                                    Request.Builder requestBuilder = original
                                                                 .newBuilder()
                                                             .url(newHttpUrl);

                                    Request request = requestBuilder
                                                      .build();
                                    return chain.proceed(request);
                              }
                          }).build();


    retrofit = new Retrofit.Builder()
            .baseUrl("https://base.url.ext/")
            .client(client)
            .addConverterFactory(GsonConverterFactory.create())
            .build();
}

While the functions called are identical to the first answer, this answer partitions the function calls out. Namely, the original url as well as the new url are stored in separate local variables. This prevents overwriting the original url until you want the OkHttpClient to do so.

Solution 7 - Java

For a cleaner code approach have a separate class for the interceptor chain like this:

    public class LanguageInterceptor implements Interceptor {
        @Override
        public Response intercept(Chain chain) throws IOException {
            HttpUrl url = chain.request()
                    .url()
                    .newBuilder()
                    .addQueryParameter("name","value")
                    .build();

            Request request = chain.request()
                    .newBuilder()
                    .url(url)
                    .build();
            Response response = chain.proceed(request);
            return response;
        }
    }

Then in the class where you defined your retrofit instance you add the instance object to it with .addInterceptor(new LanguageInterceptor()) like this:

public static Retrofit getClient() {
        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
        interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        OkHttpClient client = new OkHttpClient.Builder()
                .connectTimeout(30, TimeUnit.SECONDS)
                .readTimeout(30, TimeUnit.SECONDS)
                .addInterceptor(new LanguageInterceptor())
                .addInterceptor(interceptor)
                .build();

        if (retrofit == null) {
            retrofit = new Retrofit.Builder()
                    .baseUrl(BASE_URL)
                    .client(client)
                    .addConverterFactory(ScalarsConverterFactory.create())
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
            Log.e(TAG, "getClient: base url " + retrofit.baseUrl());
        }
        return retrofit;
    }

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMaxView Question on Stackoverflow
Solution 1 - JavaLukas LechnerView Answer on Stackoverflow
Solution 2 - Javazenghui.wangView Answer on Stackoverflow
Solution 3 - JavaSergey NikitinView Answer on Stackoverflow
Solution 4 - JavasebastianView Answer on Stackoverflow
Solution 5 - JavaAchraf AmilView Answer on Stackoverflow
Solution 6 - JavaisakbobView Answer on Stackoverflow
Solution 7 - JavaKidus TekesteView Answer on Stackoverflow