Using Absolute URLs with Retrofit

I have a HAL API that I work with, and in many cases I need to send a request (using different methods) to the URL that I get from the API. This means that I don’t want to hardcode the URL path in my api retrofit interface, but I just want to send a simple request using a modification of this URL. Now I'm using Volley, and I know that I can use OkHttp for this purpose, but I was wondering if there is a good way to do this in Retrofit?

+5
source share
4 answers

Square recently released Retrofit v2.0.0 BETA and has built-in support for dynamic URLs. Despite the fact that the library is in beta, based on what Jake Wharton told us in DroidCon NYC 2015, all apis are stable and will not change. I personally add it to my products, so it is up to you.

You will find the following links useful if you decide to make an update:
Presentation of Jake Wharton @DroidCon NYC 2015
Very good change guide

In a simple word, you can now use api annotations (e.g. @GET or @POST and others) without any path, and then you pass @URL to your api method, which the method will use to call.

---------------- Retrofitting 1.x

I understood a good way to do this and would like to share it.

The trick is to use the dynamic URL as the endpoint when creating the RestAdapter, and then the empty path in the API.

Here is how I did it:

public RestAdapter getHostAdapter(String baseHost){ RestAdapter restAdapter = new RestAdapter.Builder() .setEndpoint(baseHost) .setRequestInterceptor(requestInterceptor) .build(); return restAdapter; } 

I create my restAdapter using this method, and then I have it in my interface: (this will not work if request parameters are added to the URL. See the following answer for a solution in this case)

 public interface General { @GET("/") void getSomething(Callback<SomeObject> callback); } 

and finally using them as follows:

 getHostAdapter("YOUR_DYNAMIC_URL").create(General.class) .getSomething(new Callback<SomeObject>(){ ... }) 

Hope this helps.

+22
source

If your URL has query parameters, this solution will not work, as it will add '/' to the end of your base URL. for example if your url is

 https://www.google.com/?q=test 

then the above solution will try to send a request to

 https://www.google.com/?q=test/ 

which will fail due to the format of the mall.

What we can do is take one extra step and parse the URL. By parsing, I mean just delete all URL parameters and send them to QueryMap .

Here's how:

We should have the structure described above with a slight change in our interface

 public interface General { @GET("/") void getSomething(@QueryMap Map<String,String> queryMap, Callback<SomeObject> callback); } 

I just added QueryMap to the above interface, and now we can use this parser method:

 public static void getSomething(@NonNull String urlString, @NonNull Callback<SomeObject> callback){ Uri uri = Uri.parse(urlString); Set<String> queryParameterNames = uri.getQueryParameterNames(); String host = uri.getHost(); HashMap<String,String> queryMap = new HashMap<>(); Iterator<String> iterator = queryParameterNames.iterator(); while(iterator.hasNext()){ String queryName = iterator.next(); String queryParameter = uri.getQueryParameter(queryName); queryMap.put(queryName, queryParameter); } getHostAdapter(host) .create(General.class) .getSomething(queryMap, callback); } 

Now you can call this method as follows:

 getSomething("https://www.google.com/?q=test"); 

Enjoy the coding.

Note: QueryMap added in Retrofit v1.4.0

+3
source

I also need a path to my url, so I did this:

  @GET("/{path}") void getMatcherUrl(@Path(value = "path", encode = false) String path, @QueryMap Map<String, String> queryMap, RestCallback<MatcherResponse> matcherResponse); /** * Need to create a custom method because i need to pass a absolute url to the retrofit client * * @param urlString * @param matcherResponse */ public void getMatcherUrl(@NonNull String urlString, @NonNull RestCallback<MatcherResponse> matcherResponse) { Uri uri = Uri.parse(urlString); Set<String> queryParameterNames = uri.getQueryParameterNames(); String host = uri.getHost(); String path = (uri.getPath().startsWith("/")) ? uri.getPath().substring(1) : uri.getPath(); HashMap<String, String> queryMap = new HashMap<>(); Iterator<String> iterator = queryParameterNames.iterator(); while (iterator.hasNext()) { String queryName = iterator.next(); String queryParameter = uri.getQueryParameter(queryName); queryMap.put(queryName, queryParameter); } getApiCoreService(host) .getMatcherUrl(path, queryMap, matcherResponse); } public ApiCoreService getApiCoreService(String host) { if (StringUtils.isEmpty(host)) this.endpoint = new RestEndpoint(RemoteConfigurationManager.getInstance().getApiCore(), "ApiCore"); else this.endpoint = new RestEndpoint(host, "ApiCore"); return apiCoreService; } 
+3
source

Addendum to the two answers above. Here is a working class that uses Queryparam and runs an absolute URL

 public class VideoClient { private static final String TAG = "VideoCLient"; private final RestAdapter restAdapter; private General apiService; private String hostName; private LinkedHashMap<String, String> queryMap; private String Url_Path; public VideoClient(String BASE_URL) { Log.d(TAG,"Base url is "+BASE_URL); hostName =getHostNameAndGenerateQueryMap(BASE_URL); Gson gson = new GsonBuilder() .create(); RequestInterceptor interceptor = new RequestInterceptor() { @Override public void intercept(RequestFacade request) { } }; restAdapter = new RestAdapter.Builder() .setLogLevel(RestAdapter.LogLevel.FULL) .setEndpoint("http://"+hostName) .setClient(new OkClient()) .setConverter(new GsonConverter(gson)) .setRequestInterceptor(interceptor) .build(); } private String getHostNameAndGenerateQueryMap(String urlString) { Uri uri = Uri.parse(urlString); Url_Path = (uri.getPath().startsWith("/")) ? uri.getPath().substring(1) : uri.getPath(); Set<String> queryParameterNames = uri.getQueryParameterNames(); String host = uri.getHost(); queryMap = new LinkedHashMap<>(); Iterator<String> iterator = queryParameterNames.iterator(); while (iterator.hasNext()) { String queryName = iterator.next(); String queryParameter = uri.getQueryParameter(queryName); Log.d(TAG,"query name "+queryName +" query param "+queryParameter); queryMap.put(queryName, queryParameter); } return host; } public interface General { /*void getVideo(@Path("auth_token") String authId, @Query("et") String systemTime,@Query("service_id") String serviceID, @Query("protocol") String scheme,@Query("play_url") String url, @Query("us") String us,Callback<String> callback); */ @GET("/{path}") getVideo(@Path(value="path", encode=false)String path,@QueryMap LinkedHashMap<String, String> queryMap); } public void getVideoDetails() { Log.i("firing", "getVideoApi"); Log.d(TAG, "firing " + Url_Path + " function"); restAdapter.create(General.class).getVideo(Url_Path,queryMap, new Callback<Object>() { @Override public void success( Object o, Response response) { Log.d(TAG," Success Response is "+response ); } @Override public void failure(RetrofitError error) { Log.d(TAG, "Failure " + "Internal Error" + error); } }); } 

}

0
source

Source: https://habr.com/ru/post/1211781/


All Articles