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);
Related
I using Retrofit to making API call. All API call is working fine except one where its returning huge response around 15k records.
Issue is when made call progress bar is being shown infinitely until I get response. And as response too huge getting OOM exception.
As an solution I found that need to use #Streaming annotation. I used that but didn't get intermediate callback. I want API should return chunk of response one by one.
Please help me.
public static ServiceInterface getServiceAPIClient() {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
Gson gson = new GsonBuilder()
.setLenient()
.create();
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(
new Interceptor() {
#Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request request = chain.request();
Request.Builder builder = request.newBuilder();
builder = request.newBuilder();
if (!TextUtils.isEmpty(PrefsHelper.getAccessTokenEdrm())) {
builder.addHeader(AUTHORIZATION, PrefsHelper.getAccessTokenEdrm());
}
builder.addHeader(API_VERSION, "1.0")
.addHeader("Accept", "application/json");
request = builder.build();
return chain.proceed(request);
}
}).connectTimeout(5, TimeUnit.MINUTES) .readTimeout(5, TimeUnit.MINUTES).addInterceptor(interceptor)
.build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create(gson))
.client(client)
.build();
return retrofit.create(ServiceInterface.class);
}
API Method
#POST(EdrmConstants.SEARCH_DOCUMENTS)
#Streaming
Observable<ResponseBody> searchDocuments(#Body DocumentRequest documentRequest);
15k records is too match.
Retrofit needs time to make http request and makes serialization to your ResponseBody.class
I sure serialization takes main time.
I guess most right solution is to edit request on server side to split data on pages with 200-500 records.
I am not sure if this is a silly question (hence why I am unable to find the answer) but I was wondering if it is possible to Toast or Log output the created JSON that is being sent to the server, when it is sent.
I am simply interested to see the created JSON - I am using the following method, which is using Retrofit and .addConverterFactory(GsonConverterFactory.create(gson)):
private void addTeamMember(final List teamMemberArray,final String team_id) {
//helps with debugging regarding post requests
Gson gson = new GsonBuilder()
.setLenient()
.create();
//Retrofit is a REST Client for Android and Java by Square.
//It makes it relatively easy to retrieve and upload JSON (or other structured data) via a REST based webservice
Retrofit retrofit = new Retrofit.Builder()
//directing to the localhost which is defined in the Constants Class as BASE_URL
.baseUrl(Constants.BASE_URL)
//Add converter factory for serialization and deserialization of objects.
//Gson passed as a parameter to help with debug
.addConverterFactory(GsonConverterFactory.create(gson))
//Create the Retrofit instance using the configured values.
.build();
//The Retrofit class generates an implementation of the RequestInterface interface.
RequestInterface requestInterface = retrofit.create(RequestInterface.class);
for (Object x : teamMemberArray) {
//create new Team object
TeamMember teamMember = new TeamMember();
//setter
teamMember.setFullName(String.valueOf(x));
teamMember.setTeam_id(team_id);
Toast.makeText(getActivity(), teamMember.getFullName(),
Toast.LENGTH_LONG).show();
//create new server object
final ServerRequest request = new ServerRequest();
//make a request to set the operation to Team_Member
request.setOperation(Constants.Team_Member);
//set values entered for the new teamMember to be sent to the server
request.setTeamMember(teamMember);
Call<ServerResponse> response = requestInterface.operation(request);
/**
* Enqueue is used to Asynchronously send the request and notify callback of its response or if an error occurred
* talking to the server, creating the request, or processing the response.
*/
response.enqueue(new Callback<ServerResponse>() {
#Override
public void onResponse(Call<ServerResponse> call, retrofit2.Response<ServerResponse> response) {
ServerResponse resp = response.body();
/*Snackbars provide lightweight feedback about an operation. They show a brief message at the
bottom of the screen on mobile and lower left on larger devices. Snackbars appear above all other
elements on screen and only one can be displayed at a time.
*/
Snackbar.make(getView(), resp.getMessage(), Snackbar.LENGTH_LONG).show();
if (resp.getResult().equals(Constants.SUCCESS)) {
SharedPreferences.Editor editor = pref.edit();
Log.d("TEST VALUE", "getTeamMemberName() = " + response.body().getTeamMember().getFullName() );
Log.d("TEST VALUE", "getTeamMemberUniqueID() = " + response.body().getTeamMember().getUnique_id());
Log.d("TEST VALUE", "getTeamMemberTeamID() = " + response.body().getTeamMember().getTeamID());
editor.putString(Constants.FULL_NAME, resp.getTeamMember().getFullName());
editor.putString(Constants.UNIQUE_ID, resp.getTeamMember().getUnique_id());
editor.putString(Constants.TEAM_ID, resp.getTeamMember().getTeamID());
editor.apply();
goToQuestions();
}
progress.setVisibility(View.INVISIBLE);
}
#Override
public void onFailure(Call<ServerResponse> call, Throwable t) {
progress.setVisibility(View.INVISIBLE);
Log.d(Constants.TAG, "failed" + t);
Snackbar.make(getView(), t.getLocalizedMessage(), Snackbar.LENGTH_LONG).show();
}
});
}
}
My reasoning is that if I could see the JSON being sent across, it will help me with debugging when using Postman.
You can use OkHttpInterceptor for logging network calls with Retrofit. It will intercept any call and show logs in logger.
Add dependecy in your gradle:
compile 'com.squareup.okhttp3:logging-interceptor:3.8.0'
Then before setting your retrofit client use:
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(Level.BASIC);
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(logging)
.build();
And finally add in retrofit:
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build();
Add this in dependencies
compile 'com.squareup.okhttp3:logging-interceptor:3.4.1'
and ApiClient
public class ApiClient {
public static final String BASE_URL = "URL";
private static Retrofit retrofit = null;
public static Retrofit getClient() {
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
final OkHttpClient okHttpClient = new OkHttpClient.Builder()
.readTimeout(300, TimeUnit.SECONDS)
.connectTimeout(300, TimeUnit.SECONDS)
.addInterceptor(logging)
.build();
if (retrofit == null) {
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
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
I am using retrofit with Rxjava to get response from API as you can see the method i am using i can't see what's coming in the response and offcourse i don't need to becuase i am providing GsonConverter to retrofit but for some debugging reason i need to see the response that coming from API. How can i do this, what code i need to add.
public interface ProductApiService
{
String END_POINT = "http://beta.site.com/index.php/restmob/";
#GET(Url.URL_PRODUCT_API)
Observable<Product> getProducts(#Query("some_id") String cid);
class Creator
{
public static ProductApiService getProductAPIService() {
Gson gson = new GsonBuilder()
.setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
.create();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(ProductApiService.END_POINT)
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
return retrofit.create(ProductApiService.class);
}
}
}
You can only do this as of Retrofit 2: Change the return type to include Response:
#GET(Url.URL_PRODUCT_API)
Observable<Response<Product>> getProducts(/* ...etc... */);
You can also use Observable<Result<Product>> if you want to see all possible errors in onNext (including IOException, which normally uses onError).
Daniel Lew's approach is quick and contains the least amount of boiler plate code. However, this may force you to refactor your networking logic. Since you mention needing this for debugging purposes, perhaps using a configured OkHttpClient with Interceptors is a less intrusive strategy.
OkHttpClient httpClient = new OkHttpClient.Builder()
.addInterceptor(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Request req = chain.request();
Response resp = chain.proceed(req);
// ... do something with response
return resp;
}
})
.build();
Retrofit retrofit = new Retrofit.Builder()
.client(httpClient)
.baseUrl(ProductApiService.END_POINT)
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
I have set a global timeout in my Retrofit adapter by doing
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.setReadTimeout(20, TimeUnit.SECONDS);
okHttpClient.setConnectTimeout(20, TimeUnit.SECONDS);
retrofit = new Retrofit.Builder()
.client(okHttpClient)
.build();
Great! But I would like to set an specific timeout for certain requests
E.g.
public interface MyAPI {
#GET()
Call<Void> notImportant (#Url String url);
#GET
Call<Void> veryImportant(#Url String url);
So veryImportant calls I would like a timeout of 35 seconds but notImportant the default
Is this possible?
My research has fallen flat.
I came across this however but not sure if it will work in Retrofit
https://github.com/square/okhttp/wiki/Recipes#per-call-configuration
Thank you for reading. Please help.
You can do that by creating overloaded method of your retrofit object factory method. It's maybe look like this.
public class RestClient {
public static final int DEFAULT_TIMEOUT = 20;
public static <S> S createService(Class<S> serviceClass) {
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
OkHttpClient client = httpClient.build();
okHttpClient.setReadTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);
okHttpClient.setConnectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);
Retrofit retrofit = new Retrofit.Builder().baseUrl(BASE_URL)
.client(client)
.build();
return retrofit.create(serviceClass);
}
public static <S> S createService(Class<S> serviceClass, int timeout) {
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
OkHttpClient client = httpClient.build();
okHttpClient.setReadTimeout(timeout, TimeUnit.SECONDS);
okHttpClient.setConnectTimeout(timeout, TimeUnit.SECONDS);
Retrofit retrofit = new Retrofit.Builder().baseUrl(APIConfig.BASE_URL)
.client(client)
.build();
return retrofit.create(serviceClass);
}
}
if you want to call api with default timout, you can call it look like this.
MyAPI api = RestClient.createService(MyAPI.class);
api.notImportant();
And use the second one if you want to call api with authentication:
int timeout = 35;
MyAPI api2 = RestClient.createService(MYAPI.class, timeout);
api2.veryImportant();
Another solution is by creating different method with different OkHttpClient configuration instead of creating overloaded method. Hope this solution fix your problem.