i'm still new with singletons. I'm trying to use the DRY methode, but i'm not sure if it's correct. Below you find the class Authorization which i use to create a OkHttpClient and Retrofit.Builder. I'm not sure if it's the right way:
public class Authorization {
private static Retrofit retrofit = null;
public static Retrofit authorize(Activity activity){
final String token = SharedPreferencesMethods.getFromSharedPreferences(activity, activity.getString(R.string.token));
OkHttpClient client = new OkHttpClient();
client.interceptors().add(new Interceptor() {
#Override
public com.squareup.okhttp.Response intercept(Chain chain) throws IOException {
Request newRequest =
chain.request().newBuilder()
.addHeader("Authorization", "Bearer " + token).build();
return chain.proceed(newRequest);
}
});
if(retrofit == null){
retrofit = new Retrofit.Builder()
//10.0.3.2 for localhost
.baseUrl("http://teamh-spring.herokuapp.com")
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
The return value of the method authorize is returning a retrofit object.
Is it a singleton?
Here i call the api
CirkelsessieAPI cirkelsessieAPI = Authorization.authorize(getActivity()).create(CirkelsessieAPI.class);
Call<List<Cirkelsessie>> call = cirkelsessieAPI.getCirkelsessies();
// more code here
Thank you!
No it's not. A singleton is a design pattern that restricts the instanciation of a class to one object. I'm sure you can see why you can instantiate more than one Authorization object, and while the class "Authorization" restricts the instanciation of the class Retrofit to one object for its attribute, it can't in any way restricts someone else from instantiating another Retrofit object somewhere else.
Related
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.
I am trying to sent dynamic headers using Okhttp interceptor, but the problem I am facing is when I am calling setretrofitclient() method at the same time, then the header sent for both request are same. This is happening because as okhttp interceptor went in background thread to execute the request but at the same time in UI thread header value gets changed because of which when okhttp send the request it send new updated header.
String header;
public String getHeader() {
return header;
}
static RetrofitInterface retrofitInterface;;
public RetrofitInterface setretrofitclient(String header) {
this.header = header;
if (retrofit != null) {
return retrofit;
} else {
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
httpClient.addInterceptor(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request().newBuilder().addHeader("x-param", getHeader()).build();
return chain.proceed(request);
}
});
Retrofit retrofit = new Retrofit.Builder().addConverterFactory(GsonConverterFactory.create()).baseUrl(url).client(httpClient.build()).build();
retrofitInterface = retrofit.create(RetrofitInterface.class);
return retrofitInterface;
}
}
Can anyone please suggest me the design pattern how can I make this work for parallel requests.
Thanks.
I need to build a traffic monitor on my Android app, and I need to have stored the size of all json that I'm sending and receiving through retrofit. Using log I can see the actual size of it, but I haven't find a way to get this information so I could save it. I can't get the response.raw either since it's already been parsed to my classes. Is there any way to achieve that?
EDIT: Marked vadkou answer as the best one.
Instead of creating a new interceptor, I passed the lamda expression:
httpClient.addInterceptor( chain -> {
okhttp3.Request request = chain.request();
okhttp3.Response response = chain.proceed(request);
if(request.body()!=null) {
long requestLength = request.body().contentLength();
Log.e("SERVICE GENERATOR", " CONTENT LENGTH" + requestLength);
}
long responseLength = response.body().contentLength();
Log.e("SERVICE GENERATOR", " RESPONSE LENGTH" + responseLength);
return response;
});
Retrofit 2 uses OkHttp internally, and you could configure OkHttp without having to resort to getting raw HTTP response as in Vaiden's answer by adding a custom Interceptor while building an adapter as follows:
private Retrofit createRetrofit() {
return new Retrofit.Builder()
.baseUrl(END_POINT)
// .addConverterFactory(...)
// .addCallAdapterFactory(...)
.client(createClient())
.build();
}
private OkHttpClient createClient() {
OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder();
okHttpClientBuilder.addInterceptor(createYourInterceptor());
return okHttpClientBuilder.build();
}
The Interceptor interface among other things allows you to access request body for every request you make.
#Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
// do what you want with request.body().contentLength();
return chain.proceed(request);
}
For this you need to create custom interecptor
please reffere below example
import java.io.IOException;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
public class CustomIntercepter implements Interceptor {
#Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();///
Response response = chain.proceed(request);
// for request size
long requestLength = request.body().contentLength();
// for response size
long responseLength = response.body().contentLength();
return response;
}
}
`
Now Create Retrofit object
OkHttpClient provideOkHttpClient(CustomIntercepter customIntercepter) {
OkHttpClient.Builder okHttpClient = new OkHttpClient.Builder();
okHttpClient.cache(cache);
okHttpClient.addInterceptor(customIntercepter);
return okHttpClient.build();
}
Retrofit provideRetrofit(Gson gson, OkHttpClient okHttpClient) {
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create(gson))
.baseUrl(SERVER_URL)
.client(okHttpClient)
.build();
return retrofit;
}
You should try accessing the raw HTTP response (Get raw HTTP response with Retrofit):
You begin with a Response object.
This object has a .raw() method that returns the actual HTTP layer's reponse,
in the form of an okhttp3.Response object. Calling .body() would give you a ResponseBody object, which encapsulates the raw response.
You can get the length of the response by calling .contentLength().
I am developing Android App interacting with Twitter using Fabric and Retrofit2 libraries. I want to display search timeline. My request URL is like this: https://api.twitter.com/1.1/friends/list.json?screen_name=xxx
The response body I got is null but I got the alert of bad authentication:215 and http error 400 in the debug mode.This is probably caused by invalid authentication of the request from my app.
The Twitter developer document said requests need to be authorized with OAuth and SSL certificated.
As for the OAuth issue, I wrote the request header based on the official document of twitter developer platform https://dev.twitter.com/oauth/overview/authorizing-requests
and create the header with okhttpclient and pass it to retrofit object.
The code for OAuth issue is like this.
public class TwitterClientApiClient extends TwitterApiClient {
private static final String TAG=TwitterClientApiClient.class.getSimpleName();
private static final MainApplication app=MainApplication.getInstance();
public static final String BASE_URL = "https://api.twitter.com/";
private static Retrofit retrofit = null;
public static Retrofit getClient() {
final String authStr = app.authStr();
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
httpClient.addInterceptor(new Interceptor() {
#Override
public okhttp3.Response intercept(Interceptor.Chain chain) throws IOException {
Request original = chain.request();
Request request = original.newBuilder()
.header("Accept", "application/json")
.header("Authorization", authStr)
.method(original.method(), original.body())
.build();
Headers okHeaders = request.headers();
Log.d(TAG,okHeaders.toString());
return chain.proceed(request);
}
});
OkHttpClient client = httpClient.build();
if (retrofit==null) {
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
}
return retrofit;
}
public TwitterClientApiClient(TwitterSession session) {
super(session);
}
public FriendsService getFriendsService() {return getService(FriendsService.class);}
}
interface FriendsService {
#GET("/1.1/friends/list.json")
Call<FriendsResult> list(#Query("screen_name") String screen_name);
}
The following is the code making the request.
FriendsService apiService =
TwitterClientApiClient.getClient().create(FriendsService.class);
Call<FriendsResult> call = apiService.list(screenName);
Log.d(TAG, call.request().url().toString());
call.enqueue(new Callback<FriendsResult>() {
#Override
public void onResponse(Call<FriendsResult> call, Response<FriendsResult> response) {
//List<User> friends = response.body().getUsers();
Log.d(TAG,response.body().toString());
//Log.d(TAG, "Number of Friends: " + friends.size());
//String q = getQueryStr(friends);
//showSearchedTimeline(q);
}
#Override
public void onFailure(Call<FriendsResult>call, Throwable t) {
Log.e(TAG, t.toString());
}
});
However,according to https://oauth.net/core/1.0/#encoding_parameters
OAuth Authentication is done in three steps:
1.The Consumer obtains an unauthorized Request Token.
2.The User authorizes the Request Token.
3.The Consumer exchanges the Request Token for an Access Token.
My code which is based on references from the internet seems to do only Step 3 and thus the authentication is not complete. I wonder how to complete the whole authentication process of OAuth.
Also do I need to do sth in my code for SSL stuff?
Besides OAuth and SSL, any other security issue for request to twitter server I have overlooked?
Thanks in advance!
.header("Authorization", authStr)
Try with addHeader. You can activate the logs (useful to debug sometimes) using a logging interceptor. Ask the logger to show your headers, to see if that could be the problem. Available levels are here.
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();