Issue with Special Characters in Retrofit 2 encoding - java

So I'm looking to make a request to our api to log in a user, however there is a section that gets encoded in the Retrofit 2 method even though its set as encoded = true. The base url is https://testapi.test.ie The parameter I pass as the serverext is mdc.php?action= However even after setting encoded = true the resulting request body is: https://testapi.test.ie/mdc.php%3Faction=login_user&ts=1482924232742 where I require it to be: https://testapi.test.ie/mdc.php?action=login_user&ts=1482924232742 So I can see the issue is the ? symbol. Below is my retrofit method, if anyone can help with this I would appreciate it in order to achieve the correct
#retrofit2.http.POST("/{serverext}login_user&ts={timestamp}")
#retrofit2.http.Multipart
Call<LoginResponseModel> loginUser(#retrofit2.http.Path(value = "serverext", encoded = true) String server,
#retrofit2.http.Part(Constants.USER) String username,
#retrofit2.http.Part(Constants.PASS) String password,
#retrofit2.http.Path("timestamp") Long timestamp);

You use it incorrect. Path is path, Query is query. You need to rewrite your code to use this separately.
#retrofit2.http.POST("{serverext}")
#FormUrlEncoded
Call<LoginResponseModel> loginUser(#retrofit2.http.Path(value = "serverext", encoded = true) String server,
#retrofit2.http.Field(Constants.USER) String username,
#retrofit2.http.Field(Constants.PASS) String password,
#retrofit2.http.Query("timestamp") Long timestamp,
#retrofit2.http.Query("action") String action);
loginUser("mdc.php", username, pass, 42, "login_user")

You need to use #FormUrlEncoded . And you don't need to include package name in all declarations! just import them! its more neat and clean!
#POST("/{serverext}login_user&ts={timestamp}")
#Multipart
#FormUrlEncoded
Call<LoginResponseModel> loginUser(#Path(value = "server", encoded = true) String server,
#Part(SyncStateContract.Constants.USER) String username,
#Part(SyncStateContract.Constants.PASS) String password,
#Path("timestamp") Long timestamp);

Related

UrlBuilder query string encoding not working

WebClient urlbuilder query string has changed
String key = "bEyBOCB4SoL%2F1gI%s"
webClient.get()
.scheme("http")
.host("www.localhost:8080")
.queryParam("key", URLEncoder.encode(key, StandardCharsets.UTF_8.toString()))
.build()
... send request
query string has changed "bEyBOCB4SoL%25252F1gI%2525"
origin = "bEyBOCB4SoL%2F1gI%s"
You are triple-encoding the value.
The key string is already encoded, see the %2F which is the encoded value of /.
You then manually encode by calling URLEncoder.encode(...), which will encode % as %25.
The queryParam(...) method will then encode again, which will encode % as %25.
The result is the %25252F you see.
Change the code:
String key = "bEyBOCB4SoL/1gI%s";
.queryParam("key", key)
The result will be: bEyBOCB4SoL%2F1gI%25s

AsyncRestTemplate '#' sign encoding in query parameter

I am using AsyncRestTemplate to make an API call to Google Maps from a Springboot 1.5.2 service. Unfortunately, some of my search strings contain a pound/hashtag sign #
and are not getting encoded properly in my search parameters. I am using the exchange method.
An example below for address 05406, VT, BURLINGTON, 309 College St #10:
#Service
public class ExampleAsyncRestTemplate {
private AsyncRestTemplate asyncRestTemplate;
#Autowired
public ExampleAsyncRestTemplate() {
this.asyncRestTemplate = new AsyncRestTemplate();
}
public ListenableFuture<ResponseEntity<T>> getGeoCodedAddress() {
String googleUrl = "https://maps.googleapis.com/maps/api/geocode/json?address=05406, VT, BURLINGTON, 309 College St #10&key=some_key";
Map<String, String> uriVariables = new HashMap<>();
uriVariables.put("address", "05406, VT, BURLINGTON, 309 College St #10");
uriVariables.put("key", "some_key");
return asyncRestTemplate.exchange(googleUrl, HttpMethod.GET, new HttpEntity<>(), GoogleResponse.class, uriVariables);
}
}
The resulting URL gets encoded as:
https://maps.googleapis.com/maps/api/geocode/json?address=05406,%20VT,%20BURLINGTON,%20309%20College%20St%20#10&key=some_key
Note that the # is still in the address parameter, when it should be encoded as %23 as per the docs.
Digging into the debugger, seems like the string after the # (10&key=some_key) is being taken as the fragment of the URL. Hence why the # never gets encoded.
Has anybody been able to submit # signs in your query parameters using AsyncRestTemplate?
The only thing I've been able to come up with is replacing # with number, which actually works, but feels hacky/suboptimal.
Thanks for your help.
Note that googleUrl is a template where the encoded params get interpolated into. So you cannot provide the actual parameters as part of the url. You need to change the String into a template like this
final String googleUrl = "https://maps.googleapis.com/maps/api/geocode/json?address={address}&key={key}";
This returns the correct encoding:
https://maps.googleapis.com/maps/api/geocode/json?address=05406,%20VT,%20BURLINGTON,%20309%20College%20St%20%2310&key=some_key

Make a dynamic URL in retrofit

I want url like this
baseurl/dealer/index.php?r=rest/packInfo
I am doing like this
#FormUrlEncoded
#POST("/dealer/index.php?r=rest/{method}")
void getDealersPacks(#Path("method") String method,
#Field("cd_dealer_id") String cd_dealer_id,
#Field("country_code") String country_code,
#Field("business_type")String business_type);
And i am getting error
URL query string "r=rest/{method}" must not have replace block. For dynamic query parameters use #Query.
You are passing #Path annotation for query parameter.
You can do it this way :
#FormUrlEncoded
#POST("/dealer/index.php")
void getDealersPacks( #Query("r") String query, #Field("cd_dealer_id") String cd_dealer_id, #Field("country_code") String country_code, #Field("business_type") String business_type);
Now , pass "rest/packInfo" or any other dynamic value in query parameter, it will work.
Hope , it helps !!

How to get parameter which is containing question mark(?) from rest url in spring

i need get string from url where is "?" but controller does not accept "?"
I need send something like "Hello world?"
but I get only "Hello world"
I find solution for dot(.) -- value = "{textToTransform:.+}"
#RestController
#RequestMapping(textTransformCtrl.BASE_URI)
public class textTransformCtrl {
#Autowired
private TextTransformatorService textTransformatorService;
public static final String BASE_URI = "transform/text";
#RequestMapping(value = "{textToTransform:.+}")
public String getText(#PathVariable final String textToTransform) {
return textTransformatorService.transformText(textToTransform);
}
}
Question mark is a reserved character in URLs. It indicates where the query string starts.
If you want to send a ? as a parameter value and be able to read it on server side, you must URL encode it.
When URL encoded, Hello world? becomes Hello+world%3F.
You can use %3F to manually encode it or take a look at UriBuilder

Retrofit error URL query string must not have replace block

I have this function
#GET("/users?filters[0][field]={param}&filters[0][operator]=equals&filters[0][value]={value}")
UserDto retrieveUsersByFilters(#Path("param") String nameFilter, #Path("value") String value);
I try to call it like this :
UserDto currentUser = interfaceUser.retrieveUsersByFilters(User.LOGIN, login);
But i have error :
retrofit.RetrofitError: InterfaceUser.retrieveUsersByFilters: URL query string "filters[0][field]={param}&filters[0][operator]=equals&filters[0][value]={value}" must not have replace block.
I already test url on firefox and it work fine.
Thank's for your responses
Edit
Solution:
#GET("/users?filters[0][operator]=equals")
UserDto retrieveUsersByFilters(
#Query("filters[0][field]") String nameFilter,
#Query("filters[0][value]") String value);
Query params have their own annotation which automatically appends to the URL.
#GET("/users?filters[0][operator]=equals")
UserDto retrieveUsersByFilters(
#Query("filters[0][field]") String nameFilter,
#Query("filters[0][value]") String value);
You can read more about #Query on its Javadoc
URL="/api-mobile_prateek2.php?method=getProductById&pid="
#GET("/api-mobile_prateek2.php?method=getProductById")
Call<Product> responseproduct(#Query("pid") String pid);
dont put the pid in the #GET,, Retrofit automatically fix the url, using #Query
From the JavaDoc:
Example 1:
#GET("/friends")
Call<ResponseBody> friends(#Query("page") int page);
Calling with foo.friends(1) yields /friends?page=1.
Example with null:
Example 2:
#GET("/friends")
Call<ResponseBody> friends(#Query("group") String group);
Calling with foo.friends(null) yields /friends.
Array/Varargs Example:
Example 3:
#GET("/friends")
Call<ResponseBody> friends(#Query("group") String... groups);
Calling with foo.friends("coworker", "bowling") yields /friends?group=coworker&group=bowling.
Parameter names and values are URL encoded by default. Specify encoded=true to change this behavior.
Example 4:
#GET("/friends")
Call<ResponseBody> friends(#Query(value="group", encoded=true) String group);
Calling with foo.friends("foo+bar")) yields /friends?group=foo+bar.
Don't put your values directly in the path, but prefer in the method signature.
Not completely sure, but try something like this :
#GET("/users?filters[0][operator]=equals")
UserDto retrieveUsersByFilters(#Path("filters[0][field]") String nameFilter, #Path("filters[0][value]") String value);

Categories

Resources