4

Editing question with more details :

I understand the use of service interfaces in Retrofit. I want to make a call to a URL like this : http://a.com/b/c (and later append query parameters using a service interface).

My limitations are :

  1. I cannot use /b/c as a part of service interface (as path parameter). I need it as a part of base url. I have detailed the reason below.

  2. I cannot afford to have a resultant call being made to http://a.com/b/c/?key=val. What I need is http://a.com/b/c?key=val (the trailing slash after "c" is creating problems for my API). More details below.

My Server API changes pretty frequently, and I am facing trouble on the client side using Retrofit. The main problem is that we cannot have dynamic values (non final) passed to @GET or @POST annotations for Path Parameters (like it is possible for query parameters). For example, even the number of path parameters change when the API changes. We cannot afford to have different interfaces everytime the API changes.

One workaround to this is by forming the complete URLs, that is, an Endpoint with Base_Url + Path_Parameters.

But I am wondering why is Retrofit forcibly adding a trailing slash ("/") to the base url :

        String API_URL = "https://api.github.com/repos/square/retrofit/contributors";
        if (API_URL.endsWith("/")) {
            API_URL = API_URL.substring(0, API_URL.length() - 1);
        }
        System.out.println(API_URL);   //prints without trailing "/"

        RestAdapter restAdapter = new RestAdapter.Builder()
        .setEndpoint(API_URL)
        .build();

API_URL is always being reset to https://api.github.com/repos/square/retrofit/contributors/ by Retrofit internally (confirmed this by logging the request)

One workaround to this is by manually adding a "?" in the end to prevent "/" to be added: https://api.github.com/repos/square/retrofit/contributors?

Unfortunately, such request won't be accepted by our API.

  1. Why is Retrofit forcing this behavior ?
  2. Is there a solution for people like me who don't want a trailing slash ?
  3. Can we have variable parameters (non final) being passed to Retrofit @GET or @POST annotations ?
dev
  • 11,071
  • 22
  • 74
  • 122

1 Answers1

3

You're expected to pass the base URL to the setEndpoint(...) and define /repos/... in your service interface.

A quick demo:

class Contributor {

    String login;

    @Override
    public String toString() {
        return String.format("{login='%s'}", this.login);
    }
}

interface GitHubService {

    @GET("/repos/{organization}/{repository}/contributors")
    List<Contributor> getContributors(@Path("organization") String organization,
                                      @Path("repository") String repository);
}

and then in your code, you do:

GitHubService service = new RestAdapter.Builder()
        .setEndpoint("https://api.github.com")
        .build()
        .create(GitHubService.class);

List<Contributor> contributors = service.getContributors("square", "retrofit");
System.out.println(contributors);

which will print:

[{login='JakeWharton'}, {login='pforhan'}, {login='edenman'}, {login='eburke'}, {login='swankjesse'}, {login='dnkoutso'}, {login='loganj'}, {login='rcdickerson'}, {login='rjrjr'}, {login='kryali'}, {login='holmes'}, {login='adriancole'}, {login='swanson'}, {login='crazybob'}, {login='danrice-square'}, {login='Turbo87'}, {login='ransombriggs'}, {login='jjNford'}, {login='icastell'}, {login='codebutler'}, {login='koalahamlet'}, {login='austynmahoney'}, {login='mironov-nsk'}, {login='kaiwaldron'}, {login='matthewmichihara'}, {login='nbauernfeind'}, {login='hongrich'}, {login='thuss'}, {login='xian'}, {login='jacobtabak'}]

Can we have variable parameters (non final) being passed to Retrofit @GET or @POST annotations ?

No, values inside (Java) annotations must be declared final. However, you can define variable paths, as I showed in the demo.

EDIT:

Note Jake's remark in the comments:

Worth noting, the code linked in the original question deals with the case when you pass https://api.github.com/ (note the trailing slash) and it gets joined to /repos/... (note the leading slash). Retrofit forces leading slashes on the relative URL annotation parameters so it de-dupes if there's a trailing slash on the API url.

Bart Kiers
  • 166,582
  • 36
  • 299
  • 288
  • Worth noting: the code linked in the original question deals with the case when you pass `https://api.github.com/` (note the trailing slash) and it gets joined to `/repos/...` (note the leading slash). Retrofit forces leading slashes on the relative URL annotation so it has to de-dupe if there's a trailing slash on the API url. – Jake Wharton Dec 04 '14 at 21:34
  • @JakeWharton : Request you to review my query again. I think my question was not clear enough. Thanks ! – dev Dec 05 '14 at 07:05
  • @BartKiers : Request you to review my query again. I think my question was not clear enough. Thanks ! – dev Dec 05 '14 at 07:06