url construction in Retrofit 2.0 - android

i am trying to learn Retrofit 2.0 and tried example at http://tutorialwing.com/android-retrofit-library/
but as i go through tutorial i found that it is saying,
base url (https://api.stackexchange.com) + end url("/2.2/questions?order=desc&sort=creation&site=stackoverflow"") = final url ("https://api.stackexchange.com/2.2/search?order=desc&sort=activity&tagged=android&site=stackoverflow".
)
but how search is appended automatically although it is not present in end url.below is my code for making request to API.
public class ApiClient {
public static final String API_BASE_URL = "https://api.stackoverflow.com";
private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
private static Retrofit.Builder builder =
new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create());
public static <S> S createService(Class<S> serviceClass) {
HttpLoggingInterceptor interceptor=new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BASIC);
httpClient.addInterceptor(interceptor);
Retrofit retrofit = builder.client(httpClient.build()).build();
return retrofit.create(serviceClass);
}
}
APIinterface.java
#GET("/2.2/search/{order}/{sort}/{tagged}&site=stackoverflow")
Call<ArrayList<Questions>>loadQuestions(#Query("order")String order, #Query("sort")String sort, #Query("tagged")String tag);
but i am not getting any result. after placing interceptor i was able to see url of request is : https://api.stackoverflow.com/2.2/search/%7Border%7D/%7Bsort%7D/%7Btagged%7D&site=stackoverflow?order=desc&sort=activity&tagged=android and after hitting this url it redirect me to this url : https://api.stackexchange.com/docs/api-v1-shutdown?order=desc&sort=activity&tagged=android i am not able to find where i was made mistake. any help is appreciated.

order, sort and tagged are part of the Path of the url, so you need to use the #Path annotation for that. The only query is site=stackoverflow.
#GET("/2.2/search/{order}/{sort}/{tagged}&site=stackoverflow")
Call<ArrayList<Questions>>loadQuestions(#Path("order")String order, #Path("sort")String sort, #Path("tagged")String tag, #Query("site") siteName);
should yeld the url you want.
Edit: if you want to query https://api.stackexchange.com/2.2/search?order=desc&sort=activity&tagged=android&site=stackoverflow then your definition should be
#GET("/2.2/search")
Call<ArrayList<Questions>>loadQuestions(#Query("order")String order, #Query("sort")String sort, #Query("tagged")String tag, #Query("site") siteName);
or alternatively you can use #QueryMap to provide a single argument

Related

Retrofit, OkHttp3 and Spring occasional error The request was rejected because the URL contained a potentially malicious String ";"

we are having a network error, and are not sure what could be causing it. We upload data from an Android app, and most of the time it works great.
Data are sent with Retrofit and OKHttp3 using an interface:
private static String BASE_URL = "https://backend.ourapp.com/api/";
private static String cert1 = ...;
private static String cert2 = ...;
private static String cert3 = ...;
public static Retrofit retrofit;
static Gson gson = new GsonBuilder()
.setLenient()
.create();
static CertificatePinner certificatePinner = new CertificatePinner.Builder()
.add("backend.ourapp.com", cert1)
.add("backend.ourapp.com", cert2)
.add("backend.ourapp.com", cert3)
.build();
public static HttpLoggingInterceptor logging =
new HttpLoggingInterceptor()
.setLevel(HttpLoggingInterceptor.Level.BODY);
public static OkHttpClient okHttpClient = new OkHttpClient.Builder()
.readTimeout(180, TimeUnit.SECONDS)
.connectTimeout(180, TimeUnit.SECONDS)
.certificatePinner(certificatePinner)
.addInterceptor(logging)
.build();
public static Retrofit getClient(String url) {
if (retrofit == null) {
retrofit = new Retrofit.Builder()
.baseUrl(url)
.addConverterFactory(GsonConverterFactory.create())
.client(okHttpClient)
.build();
}
return retrofit;
}
public static ApiInterface apiInterface() {
retrofit = null;
return ApiClient.getClient(BASE_URL).create(ApiInterface.class);
}
But then all of a sudden, and randomly, we start having issues. Error from backend log is:
ERROR org.apache.juli.logging.DirectJDKLog [http-nio-7200-exec-1] Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception
org.springframework.security.web.firewall.RequestRejectedException: The request was rejected because the URL contained a potentially malicious String ";"
We understand this is part of StrictHttpFirewall, and aren't looking to use .setAllowSemicolon(true);.
But we are confused why this is happening, because we aren't, as far as we know, appending anything to our URL. It's an error that also seems to pop up randomly, and then disappear randomly. It also isn't universal- a user will start having the problem while others are OK, and then they will be fine. It typically happens with mobile data networks and not wifi.
Suggestions?? Other things we should look at? Don't suppose it could somehow be certificate related? We have set the timeouts fairly liberally because our app is used on networks that are often slow, but if this particular error doesn't happen, upload is usually successful. We are using retrofit 2.4 and okhttp3 3.10.
Thanks
It appears that the problem is resolved by simply updating Retrofit to 2.9.0 and OkHttp3 to 4.9.1.

java.net cannot resolve Domain name

So, I was doing my project on localhost and everything ran smooth. I was able to make request call to the server and getting the response from my android. No problem. Then I got a ec2 from AWS and did't map to any domain name. SO, When I use curl or postman to make the request it works totally fine. Everything works great. But the same URL I try to make a request from my Retrofit it says
HTTP FAILED: java.net.UnknownHostException: Unable to resolve host "ec2-11-130-81-251.ap-south-1.compute.amazonaws.comapi": No address associated with hostname
I also made sure that I have given internet permission in my phone and everything. So, is it a must to have a domain name when making network request from an android phone? is there any way to bypass such things?
here is my retrofit singleton class if it finds useful. Thanks
public class ApiClient {
// public static final String BASE_LOCAL_URL = "http://192.168.1.4:3000/";
// public static final String BASE_LOCAL_EMULATOR_URL = "http://10.0.2.2:3000/";
public static final String SERVIER_LOGIN="ec2-11-130-81-251.ap-south-1.compute.amazonaws.comapi";
public static final String BASE_URL = SERVIER_LOGIN;
private static Retrofit retrofit = null;
private ApiClient() {
if (retrofit != null) {
throw new RuntimeException("Use getInstance() method to get the single instance of this class.");
}
}
public static synchronized Retrofit getClient(Context context) {
if (retrofit == null) {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.level(HttpLoggingInterceptor.Level.BODY);
AuthInterceptor authInterceptor = new AuthInterceptor(context);
OkHttpClient client = new OkHttpClient.Builder().
addInterceptor(authInterceptor).
readTimeout(60, TimeUnit.SECONDS)
.writeTimeout(60, TimeUnit.SECONDS)
.connectTimeout(60, TimeUnit.SECONDS)
.addInterceptor(interceptor)
.build();
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create(getGson()))
.client(client)
.build();
return retrofit;
}
return retrofit;
}
private static Gson getGson() {
return new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS").create();
}
}
Resolved by adding a slash in your base URL. That is if your base URL is www.some_base_url.com it should be www.some_base_url.com/ when initiating a retrofit instance. So. Make sure you're adding a slash in the end if it gives that error.

Retrofit Dynamic json response latest not running

There is an issue in the retrofit library that I am facing in the dynamic data JSON response.
For example, if any key in the JSON is of int type and due to some reason the particular key type is changed to string. Now corresponding to the first JSON response when the key was of int type the model class was created. Now my question is I want to handle the updated string format JSON. How should I solve this task?
Below is the ApiClient class of the retrofit.
public class ApiClient
{
public static final String BASE_URL = "http:***********";
private static Retrofit retrofit = null;
public static Retrofit getClient() {
if (retrofit==null) {
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
I have got some solutions which use the rest adapter but I want to solve using the above format. How I should do please guide.

Is there a way to get passed in post request parameters during building process in Retrofit2.1.0?

I am trying to compute a checksum from HTTP arguments dynamically. And then I would like to add this checksum as an HTTP argument.
I need to get the fields that are passed in as parameters first, but it looks like retrofit can only access url query parameters.
#Gordak shows the way to get query parameter, but what I want to achive, if any possible, to get post parameters in the request chain.
Okay, here we go.
First, build your OkHTTP client and retrofit object.
OkHttpClient client = httpBuilder
.addNetworkInterceptor(INTERCEPTOR_REQUEST_ADD_CHECKSUM)
.build();
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.baseUrl("https://my.domain.com")
.build();
Then, you need to define your interceptor :
private static final Interceptor INTERCEPTOR_REQUEST_ADD_CHECKSUM = new Interceptor() {
#Override
public Response intercept(Interceptor.Chain chain) throws IOException {
HttpUrl url = chain.request().url();
String param1 = url.queryParameter("param1");
String param2 = url.queryParameter("param2");
String chk = aMethodToComputeChecksum(param1,param2);
url = url.newBuilder().addQueryParameter("checksum", chk).build();
Request request = chain.request().newBuilder().url(url).build();
return chain.proceed(request);
}
Maybe it will help - try to compute this parameter once and write it in RequestInterceptor

Retrofit URL with headers and params

I am having some troubles with Retrofit 2 library. I want to send headers and parameters with https request, I have the following url from log:
https://api.trakt.tv/movies/popular(page='1')?limit=10&extended=full,images
I got 404 status code. The above Url is correct?
String ENDPOINT = "https://api.trakt.tv/";
#GET("movies/popular(page='{page}')?limit=10&extended=full,images")
public Observable<PopularMoviesResponse> getPopularMovies(#Header("trakt-api-version") String trakt_api_version,
#Header("trakt-api-key") String trakt_api_key,
#Path("page") String page);
/********
* Helper class that sets up a new services
*******/
class Creator {
public static MovieService newSurveiesService() {
Gson gson = new GsonBuilder()
.setDateFormat("dd/MM/yyyy hh:mm:ss")
.create();
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(MovieService.ENDPOINT)
.client(client)
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
return retrofit.create(MovieService.class);
}
}
It looks like your url in #GET is wrong, based on the fact that you said the url #CaseyB provided works.
#Get("movies/popular?page={page}&limit=10&extended=full,images")
Alternatively, you could use the #Query annotation to have Retrofit to take care of the query string for you:
#Get("movies/popular")
public Observable<PopularMoviesResponse> getPopularMovies(
#Header("trakt-api-version") String trakt_api_version,
#Header("trakt-api-key") String trakt_api_key,
#Query("page") int page,
#Query("limit") int limit,
#Query("extended") String extended);

Categories

Resources