Convert OkHttpClient to Retrofit 2 - java

I am using Part 1 code to call an API that run successfully but I want to implement the logic with Retrofit2. I have done implementation in Part 2 but code always comes with response FORBIDDEN.
The URL takes text file as byte array for uploading. Can any one have a look at the code and guide me what I am doing wrong
Part 1
public void testcall(byte[] bytesArray) {
OkHttpClient client = new OkHttpClient();
RequestBody formBody = RequestBody.create(MediaType.parse("application/json") , bytesArray);
Request request = new Request.Builder()
.url("https://logs-01.loggly.com/bulk/Token/tag/file_uploadTest")
.post(formBody)
.build();
Response response = client.newCall(request).execute();
}
Part 2
public interface ApplicationLog {
#POST("/")
LogResponse uploadLog(#Body RequestBody body);
}
public class ApplicationLogSender {
private String url;
public ApplicationLogSender(String url) {
this.url = url;
}
public ApplicationLog applicationLogSenderBuilder() {
System.out.println("Log url" + url);
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(url)
.addConverterFactory(JacksonConverterFactory.create())
.build();
return retrofit.create(ApplicationLog.class);
}
}
public void testcall(byte[] bytesArray) {
RequestBody formBody = RequestBody.create(MediaType.parse("application/json") , bytesArray);
// I also tried with "Text/plain but no success"
LogResponse = builder.uploadLog(formBody).enqueue // This line always throw Forbidden
}

Related

add header for every request of retrofit2

I am add a interpreter in retrofit like this:
public static Retrofit InitRetrofitOkhttp(String configKey) {
String tenantId = MyContext.getCurrentTenantId() == null ? "" : MyContext.getCurrentTenantId().toString();
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.connectTimeout(10, TimeUnit.SECONDS);
builder.readTimeout(20, TimeUnit.SECONDS);
builder.writeTimeout(20, TimeUnit.SECONDS);
builder.retryOnConnectionFailure(true);
builder.addInterceptor(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Request original = chain.request();
Request.Builder requestBuilder = original.newBuilder()
.header(MyContext.VERIFY_TENANT_ID, tenantId);
Request request = requestBuilder.build();
return chain.proceed(request);
}
});
Config config = ConfigService.getAppConfig();
String baseUrl = config.getProperty(configKey, "127.0.0.1");
OkHttpClient client = builder.build();
Retrofit.Builder retrofitBuilder = new Retrofit.Builder();
retrofitBuilder.client(client);
retrofitBuilder.baseUrl(baseUrl);
retrofitBuilder.addConverterFactory(GsonConverterFactory.create());
Retrofit sRetrofit = retrofitBuilder.build();
return sRetrofit;
}
what I want to do is add different tenant_id in every http request, but it seems only the first time initial retrofit add interpreter(I could not debbugging in interpreter), what should I do to make it work? I did not know I do like this works.
Move
String tenantId = MyContext.getCurrentTenantId() == null ? "" : MyContext.getCurrentTenantId().toString();
into intercept method

How to send Audio File Using Retrofit

I am Trying to send audio file using Retrofit but ResponseBody always null and Status is 500 internal server error ,I tried a lot of different things but nothing Works
Postman Screenshots:
body
header
My Client:
public class AudioClient {
private static Retrofit retrofit = null;
public static Retrofit getClient(Context context) {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
if (retrofit == null) {
retrofit = new Retrofit.Builder()
.baseUrl(context.getString(R.string.base_url)).client(client)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
addAudioComment method:
#Multipart
#POST("api/Comment/AddSoundComment")
Call<AudioComment> addAudioComment(#Header("Authorization") String contentRange,
#Part("referenceType") RequestBody ReferenceType,
#Part("referenceId") RequestBody ReferenceID,
#Part("parentId") RequestBody ParentID,
#Part MultipartBody.Part AudioComment);
The Request :
File audioFile = new File(mRecordedFilePath);
RequestBody reqFile = RequestBody.create(MediaType.parse("audio/*"), audioFile);
audioPart = MultipartBody.Part.createFormData("AudioComment", audioFile.getName(), reqFile);
Call<AudioComment> apiCall = service.addAudioComment(String.valueOf(SharedPreferencesHelper.getLogInToken(CommentsActivity.this)),
reqRefType, reqRefId, reqParentId, audioPart);
//apiCall =service.addAudioComment();
apiCall.enqueue(new Callback<AudioComment>() {
#Override
public void onResponse(Call<AudioComment> call, Response<AudioComment> response) {
Log.i("RETROFIT", "onResponse Called");
AudioComment postResult = response.body();
}
#Override
public void onFailure(Call<AudioComment> call, Throwable t) {
String err = t.getMessage() == null ? "" : t.getMessage();
showError(R.string.service_failure);
Log.e("RETROFIT", err);
setRefreshing(false);
dismissProgress();
}
});
In my case I remove #Multipart from interface and replaced
#part with #Body RequestBody requestBody. Eg. as follows,the second parameter is audio file.
public interface APIInterface {
#POST(url)
Call<String> postAudioAndGetResponse(#Header("Subscription-Key") String keyValue,
#Body RequestBody requestBody,
#Query("language") String language);
}
and called above method like this
File file = new File(audioFileName);
RequestBody requestBody = RequestBody.create(MediaType.parse("audio/*"), file);
Call<String> str = apiInterface.postAudioAndGetResponse(speechSubscriptionKey, requestBody,"en-IN");
and it worked .
Hope it will help someone. :)

Basic authorization in retrofit

Interface:
#GET("burrowedbooks/")
Call<JsonArray> getCategoryList(#Header("Authorization") String token);
Usage:
private LibraryAPi service;
Retrofit retrofit = new Retrofit.Builder()
//.client(client)
.baseUrl(String.valueOf(R.string.base_url))
.addConverterFactory(GsonConverterFactory.create())
.build();
service = retrofit.create(LibraryAPi.class);
// Extract token from Shared Preferences.
SharedPreferences prefs = getActivity().getSharedPreferences(getString(R.string.login_data), MODE_PRIVATE);
String token = "Bearer "+prefs.getString("token","");
Call<JsonArray> categoryListResponseCall = service.getCategoryList(token);
categoryListResponseCall.enqueue(new Callback<JsonArray>() {
#Override
public void onResponse(Call<JsonArray> call, Response<JsonArray> response) {
int statusCode = response.code();
Toast.makeText(getContext(), ""+statusCode, Toast.LENGTH_SHORT).show();
}
#Override
public void onFailure(Call<JsonArray> call, Throwable t) {
}
});
I'm trying to send authentication token stored in shared preferences. The code above is not working. It returns 403 forbidden status code. What is the correct way to send authentication header?
You are wrong at .baseUrl(String.valueOf(R.string.base_url))
You should get string from resource using .baseUrl(getActivity().getString(R.string.base_url))
But your code will not send data to the server and onFailure would be called.
If you get the string properly and still are getting 403, you may want to verify your back end implementation using postman.
Also you can create a custom interceptor to add your header automatically on new requests.
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
httpClient.addInterceptor(new Interceptor() {
#Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request original = chain.request();
Request request = original.newBuilder()
.header("Authorization", token)
.method(original.method(), original.body())
.build();
return chain.proceed(request);
}
}
OkHttpClient client = httpClient.build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
Also, check if token is received good from SharedPreferences. Looks odd how you read it.

Basic authentication with retrofit2 for cloudinary

Im trying to authenticate to Cloudinary API service using the below code but i get 401 unauthorized error, it expects credentials in this format https://API_KEY:API_SECRET#..., when i substitute with actual values it works great with browser/postman but fails with retrofit2, below is my code.
// create and initialize retrofit2 client
public static OkHttpClient getClient(){
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(Level.BASIC);
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request().newBuilder()
.addHeader("API_KEY","API_SECRET")
.addHeader("Accept","Application/JSON").build();
return chain.proceed(request);
}
})
.addInterceptor(interceptor)
.build();
return client;
}
private static Retrofit retrofit = null;
public static Retrofit getClient(String baseUrl){
if (retrofit == null){
retrofit = new Retrofit.Builder()
.client(getClient())
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
// Interface with get methods to access image resources
public interface CloudinaryService {
#GET("resources/image")
Call<imageresponse> getImageResource();
}
// Util class to make requests
public class ApiUtils {
private static final String BASE_URL = "http://api.cloudinary.com/v...";
public static CloudinaryService getImageService(){
return RetrofitClient.getClient(BASE_URL)
.create(CloudinaryService.class);
}
}
Any help fixing the error will be highly appreciated, not sure if need custom converter. thanks
***** Edit******
public static String credentials = Credentials.basic(API_KEY,API_SECRET);
OkHttpClient client = new OkHttpClient.Builder()
// .authenticator(new Authenticator() {
// #Override
// public Request authenticate(Route route, Response response) throws IOException {
//
// return response.request().newBuilder().header("Authorization", credentials).build();
// }
// })
.addInterceptor(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Request request = (chain.request().newBuilder()
.header("Accept","Application/JSON")
.header("Cache-Control", "public, max-age=" + 60)
.header("Authorization",credentials).build());
return chain.proceed(request);
}
})
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.addInterceptor(loggingInterceptor)
.addInterceptor(provideOfflineCacheInterceptor())
.addNetworkInterceptor(provideCacheInterceptor())
.cache(getCache())
.build();
return client;
}
I was able to fix the issue with adding authenticator to the builder.
.authenticator(new Authenticator() {
#Override
public Request authenticate(Route route, Response response) throws IOException {
return response.request().newBuilder().header("Authorization", credentials).build();
}
})
thanks for all your help.
request = chain.request();
builder = request.newBuilder();
if (TextUtils.isEmpty(request.header(AUTH)) && UserPreference.getInstance().isSignin())
builder.addHeader(AUTH, UserPreference.getInstance().getAccessToken());
if (NetUtil.hasNetwork(GridInnApplication.getInstance()))
builder.header(USER_AGENT, userAgent);
else
builder.cacheControl(CacheControl.FORCE_CACHE);
request = builder.build();
Response response = chain.proceed(request);
if (NetUtil.hasNetwork(GridInnApplication.getInstance())) {
String cacheControl = request.cacheControl().toString();
return response.newBuilder()
.header(CACHE_CONTROL, cacheControl)
.removeHeader(PRAGMA)
.build();
} else {
return response.newBuilder()
.addHeader(CACHE_CONTROL, CACHE_CONTROL_ONLY_CACHED)
.removeHeader(PRAGMA)
.build();
}
//you can results before returing intercept
The answer provided by leafNext will work but will cause every request to be sent twice - The authenticator only kicks in if the server responds with 401. You send the request, get 401 and then send it again with proper credentials.
The correct solution is to provide the credentials from the get go, using the interceptor. It's similar to what you tried to do originally, but you got the syntax wrong. The expected format is basic authentication.
.addInterceptor(new Interceptor() {
#Override
public Response intercept(Interceptor.Chain chain) throws IOException {
// Request customization: add request headers
return chain.proceed(chain.request().newBuilder()
.header("Authorization", credentials).build());
}
});
Where credentials should follow the basic authentication protocol: Assuming the Api key is key and the secret is secret, you base64-encode the expression key:secret and prefix it with Basic. In this example the value of credentials should end up like so:
Basic a2V5OnNlY3JldA==
Edit - Added a fully working independent code bit to verify basic auth is working for okhttp (and thus with retrofit when using okhttp):
public int testBasicAuth() throws IOException {
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Request request = (chain.request().newBuilder()
.header("Authorization",okhttp3.Credentials.basic(KEY, SECRET)).build());
return chain.proceed(request);
}
}).build();
Request request = new Request.Builder()
.url("https://api.cloudinary.com/v1_1/[cloud_name]/resources/image")
.build();
int code = client.newCall(request).execute().code();
return code; // 200
}

How can i post data with utf8 from Android to server

I want POST data from android to server, my server language is PHP.
When POST data, this data save with strange characters , such as this : وب تیحی . this data is utf8 characters and this data is not OK!. For requests i use Retrofit2
My POST request is :
private void sendComment(String cmPostID, String name, String email, String content) {
Gson gson = new GsonBuilder()
.setLenient()
.create();
OkHttpClient client = new OkHttpClient();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Constants.BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
Retrofit_ApiInterface requestInterface = retrofit.create(Retrofit_ApiInterface.class);
comment = new Comment();
comment.setComment_post_ID(cmPostID);
comment.setComment_author(name);
comment.setComment_author_email(email);
comment.setComment_content(content);
ServerRequest request = new ServerRequest();
request.setOperation(Constants.COMMENT);
request.setComment(comment);
Call<ServerResponse> response = requestInterface.cmOperation(request);
response.enqueue(new Callback<ServerResponse>() {
#Override
public void onResponse(Call<ServerResponse> call, Response<ServerResponse> response) {
ServerResponse resp = response.body();
if (resp.getResult().equals(Constants.SUCCESS)) {
sendLoad.setVisibility(View.INVISIBLE);
TastyToast.makeText(context, StringEscapeUtils.unescapeHtml4(resp.getMessage()), TastyToast.LENGTH_LONG,
TastyToast.SUCCESS);
closeCommentDialog();
} else {
sendCommentImage.setVisibility(View.VISIBLE);
sendLoad.setVisibility(View.INVISIBLE);
TastyToast.makeText(context, StringEscapeUtils.unescapeHtml4(resp.getMessage()), TastyToast.LENGTH_LONG,
TastyToast.ERROR);
}
}
#Override
public void onFailure(Call<ServerResponse> call, Throwable t) {
sendLoad.setVisibility(View.INVISIBLE);
sendCommentImage.setVisibility(View.VISIBLE);
TastyToast.makeText(context, "Faild, send Again please", TastyToast.LENGTH_LONG, TastyToast.ERROR);
}
});
}
How can i fix this problem, and send data with UTF8 ?

Categories