2

As stated in the Retrofit documentation above the @Query annotation:

Passing a List or array will result in a query parameter for each non-null item.


As of now my call looks something like this:

@GET("questions")
Call<List<QuestionHolder>> getQuestionsExcludingTheSpecified(
        @Query("exclude_ids") long[] excludedQuestionIds
);

This works but results in fairly long URLs quite fast.

E.g. for excludedQuestionIds = new long[]{1L, 4L, 16L, 64L} the request URL already will be /questions?exclude_ids=1&exclude_ids=4&exclude_ids=16&exclude_ids=64.


Is there an easy way to exchange this behaviour resulting in arrays formatted as exclude_ids=[1,4,16,64] or something similar?

What came to my mind yet was, to:

  • use JsonArray as parameter, but then I need to convert every array / list before making the call
  • intercept every request and compress duplicated keys
  • override the built-in @Query decorator

Any ideas?

Endzeit
  • 4,810
  • 5
  • 29
  • 52

1 Answers1

1

I decided to go with the Interceptor approach. I simply change any outgoing request that includes more than one value for a single query parameter.

public class QueryParameterCompressionInterceptor implements Interceptor {

    @Override
    public Response intercept(Interceptor.Chain chain) throws IOException {
        Request request = chain.request();

        HttpUrl url = request.url();
        for (String parameterName : url.queryParameterNames()) {
            List<String> queryParameterValues = url.queryParameterValues(parameterName);

            if (queryParameterValues.size() > 1) {
                String formattedValues= "[" + TextUtils.join(",", queryParameterValues) + "]";

                request = request.newBuilder()
                        .url(
                                url.newBuilder()
                                        .removeAllQueryParameters(parameterName)
                                        .addQueryParameter(parameterName, formattedValues)
                                        .build()
                        ).build();
            }
        }

        return chain.proceed(request);
    }

non android solution

TextUtils is part of the Android SDK, in case you're not developing for Android you might exchange TextUtils.join for a method like this:

    public static String concatListOfStrings(String separator, Iterable<String> strings) {
        StringBuilder sb = new StringBuilder();

        for (String str : strings) {
            sb.append(separator).append(str);
        }

        sb.delete(0, separator.length());

        return sb.toString();
    }
}

You may also have a look at this SO question for more solutions regarding the concatenation.

Community
  • 1
  • 1
Endzeit
  • 4,810
  • 5
  • 29
  • 52