75

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);
Max
  • 1,534
  • 1
  • 18
  • 24
  • If you managed to add a query parameter in the interceptor, could you add the code in your question or in a response of your own question? – Louis CAD Oct 11 '15 at 00:35

7 Answers7

155

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();
Rohit Arya
  • 6,751
  • 1
  • 26
  • 40
Lukas Lechner
  • 7,881
  • 7
  • 40
  • 53
  • 16
    `httpUrl()` method in the `Request` object was changed to `url()` in the latest version of the OkHttp – Singed Mar 15 '16 at 15:05
  • 19
    `interceptors()` returns immutable `List` in `3.2.0`. Use `addInterceptor()` in `OkHttpClient.Builder` instead. – Yaroslav Mytkalyk Jun 10 '16 at 08:30
  • 4
    The added parameter will be set in GET, it can be an issue if you need to use another request type. – tryp Oct 25 '16 at 08:55
13

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);
fawaad
  • 341
  • 6
  • 12
zenghui.wang
  • 131
  • 1
  • 3
7

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.

Achraf Amil
  • 1,275
  • 16
  • 20
5

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();
Vasily Kabunov
  • 6,511
  • 13
  • 49
  • 53
Sergey Nikitin
  • 807
  • 8
  • 23
3

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.

Vasily Kabunov
  • 6,511
  • 13
  • 49
  • 53
sebastian
  • 2,610
  • 2
  • 17
  • 28
  • 4
    It absolutely doesn't explain how to add a Query Parameter. It just explains how to intercept, but I only found a way to add headers, and the OP and me want to add a query parameter – Louis CAD Oct 11 '15 at 00:34
  • 3
    You can modify the request chain to your needs, see the OkHttp documentation for details. (example: chain.proceed(chain.request().newBuilder().url(chain.request().httpUrl().newBuilder().addQueryParameter("name", "value").build()).build()); // http://square.github.io/okhttp/javadoc/com/squareup/okhttp/HttpUrl.Builder.html#addQueryParameter-java.lang.String-java.lang.String-) – sebastian Oct 12 '15 at 12:23
  • You're right. As the API changed, it was harder to find how to add the query parameters, so your solution didn't helped me, until I found httpurl also had a newBuilder method. I think you should add it to your question – Louis CAD Oct 12 '15 at 12:27
2

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.

isakbob
  • 1,439
  • 2
  • 17
  • 39
2

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;
    }
Kidus Tekeste
  • 651
  • 2
  • 10
  • 28
  • 1
    Just awesome! Exactly what I needed, I had to support many languages (in a biggg project) and this is the best solution :) – Makalele Jan 20 '21 at 14:45