So I have this POST request made to the server and based on an argument the server will return error message within the errorBody() of Retrofit. I am trying to handle that Plain Text error returned by the server and then display it to the user within my Android application which uses Java. Below is my current attempt but this is giving me this error in Logcat:
#Url cannot be used with #POST URL (parameter #1)
Here is 400 response from the server:
Interface:
public interface ChangePickLocationClient
{
#GET
Call<ResponseBody> checkItem(#Url String url, #Header("Authorization") String authToken);
#GET
Call<String> getStringError(#Url String url, #Header("Authorization") String authToken);
#POST("Pick/ChangePickLocationAcceptChange")
Call<String> changePickLocationPOST(#Url String url, #Header("Authorization") String authToken, #Body
ChangePickLocationPostModel changePickLocationPostModel);
}
Implementation:
private static final String BASE_URL = "http://00.00.00.1234/api/";
Gson mGson = new Gson();
Retrofit retrofit = new Retrofit.Builder().client(new OkHttpClient())
.baseUrl(BASE_URL).addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create(mGson))
.build();
ChangePickLocationClient ChangePickLocationClient =
retrofitPOST.create(ChangePickLocationClient.class);
String itemNumber = itemNumberValue.getText().toString();
newPickLocationValue.setText(newPickLocationValue.getText().toString().toUpperCase());
String newPickLocation = newPickLocationValue.getText().toString();
String token = globalClass.getActiveToken();
final ChangePickLocationClient mChangePickLocationInterface =
retrofit.create(ChangePickLocationClient.class);
Call<String> mCallErrorPOST = mChangePickLocationInterface.changePickLocationPOST
(postUrl, "Bearer " + globalClass.getActiveToken(),
changePickLocationPostModel);
call.enqueue(new Callback<ChangePickLocationPostModel>()
{
#Override
public void onResponse(Call<ChangePickLocationPostModel> call,
Response<ChangePickLocationPostModel> response)
{
String mPlainTextResponse = null;
try {
if(response.errorBody() != null)
{
mPlainTextResponse = response.errorBody().string();
}
} catch (IOException e)
{
e.printStackTrace();
}
Toast.makeText(ChangePickLocation.this, mPlainTextResponse
,Toast.LENGTH_SHORT).show();
}
#Override
public void onFailure(Call<ChangePickLocationPostModel> call, Throwable t)
{
Toast.makeText(ChangePickLocation.this, "Unknown server error!"
,Toast.LENGTH_SHORT).show();
}
});
When the response is 400, the second call being made needs to be a clone() call. This is because the Call cannot be used more than once as stated in the documentation.
use this:
call.clone().enqueue(new Callback<ChangePickLocationPostModel>()
instead of
call.enqueue(new Callback<ChangePickLocationPostModel>()
Hi Im trying to add a bearer token to a retrofit call in java, but i cant seem to pass it.
Currently Im logging in with one method and this creates a bearer token and im trying to add the token to the Get Call, but its just returning a 401 error, have I added the token to the call correctly?
#GET("diagnosis/configuration")
Call<ResponseBody> getFavourites (#Query("favourite") Boolean fave,#Header("Bearer Token") String authHeader);
#POST("auth/login")
Call<LoginResponse> postLogin (#Body LoginCredentialsBody body);
public class LoginApiStepDefinition extends TestBaseFix {
Retrofit retrofit = super.buildRetrofit(super.buildOkHttpClient());
RetrofitCallsLogin call = retrofit.create(RetrofitCallsLogin.class);
RetrofitCallsGetFavourites favecall = retrofit.create(RetrofitCallsGetFavourites.class);
private Response<LoginResponse> responseBody;
private String favouritesResponseBody;
String usernameValue;
String passwordValue;
#And("I login with {string} and {string} to return login token")
public void iLoginWithAndToReturnLoginToken(String username, String password) throws Exception {
LoginApi(username, password);
}
public String LoginApi(String username, String password) throws Exception {
usernameValue = username;
passwordValue = password;
//gets fixture ids for the dates
LoginCredentialsBody login = new LoginCredentialsBody();
login.setPassword(passwordValue);
login.setUsername(usernameValue);
String responseBody = call.postLogin(login).execute().body().toString();
String requiredString = responseBody.substring(responseBody.indexOf("=") + 1, responseBody.indexOf(","));
System.out.println(requiredString);
return token;
}
#Then("I get the list of favourites with {string} and {string}")
public void iGetTheListOfFavouritesWithAnd(String username, String password) throws Exception {
String favouritesResponseBody = favecall.getFavourites(true, LoginApi(username, password)).execute().body().toString();
System.out.println(favouritesResponseBody);
}
}
To add bearer token in retrofit, you have to create a class that implements Interceptor
public class TokenInterceptor implements Interceptor{
#Override
public Response intercept(Chain chain) throws IOException {
//rewrite the request to add bearer token
Request newRequest=chain.request().newBuilder()
.header("Authorization","Bearer "+ yourtokenvalue)
.build();
return chain.proceed(newRequest);
}
}
Now add your Interceptor class in OKHttpClient object and add that obejct in Retrofit object:
TokenInterceptor interceptor=new TokenInterceptor();
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(interceptor)
.build();
Retrofit retrofit = new Retrofit.Builder()
.client(client)
.baseUrl("add your url here")
.addConverterFactory(JacksonConverterFactory.create())
.build();
these three class will be your final setup for all types of call
for first call(Login) you do not need to pass token and after login pass jwt as bearer token to authenticate after authentication do not need to pass
public class ApiUtils {
private static final String BASE_URL="https://abcd.abcd.com/";
public ApiUtils() {
}
public static API getApiService(String token){
return RetrofitClient.getClient(BASE_URL,token).create(API.class);
}}
2.Using ApiUtils.getapiService you can get the client ,pass jwt or bearer token
public class RetrofitClient {
public static Retrofit retrofit=null;
public static Retrofit getClient(String baseUrl, String token){
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder()
.readTimeout(60,TimeUnit.SECONDS)
.connectTimeout(60,TimeUnit.SECONDS)
.addInterceptor(interceptor)
.addInterceptor(new Interceptor() {
#NotNull
#Override
public Response intercept(#NotNull Chain chain) throws IOException {
Request request=chain.request().newBuilder()
.addHeader("Authorization", "Bearer " + token)
.build();
return chain.proceed(request);
}
}).build();
if(retrofit==null||token!=null){
retrofit= new Retrofit.Builder()
.baseUrl(baseUrl)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}}
3 In this Interface you can create methods for get or post requests
public interface API {
#POST("/Api/Authentication/Login")
Call<JsonObject> login(#Body Model userdata);
#POST("/api/Authentication/ValidateSession")
Call<JsonObject> validateSession(#Body MyToken myToken);
#POST("/api/master/abcd")
Call<JsonObject> phoneDir(#Body JsonObject jsonObject);
#Multipart
#POST("/api/dash/UploadProfilePic")
Call<JsonObject> uploadProfile(#Part MultipartBody.Part part);
#FormUrlEncoded
#POST("/api/dashboard/RulesAndPolicies")
Call<JsonObject> rulesAndProcess(#Field("ct") int city);
#FormUrlEncoded
#POST("/api/dashboard/RulesAndPolicies")
Call<JsonObject> rulesAndProcess(
#Field("city") int city,
#Field("department") String department,
#Field("ctype") String ctype
);
Trying to send form data to the server via Retrofit but unable to request to the server. I want to post an image array with their data.
val builder: MultipartBody.Builder = MultipartBody.Builder().setType(MultipartBody.FORM);
builder.addFormDataPart("device_id",device_UDID)
builder.addFormDataPart("device_token",device_token)
builder.addFormDataPart("device_type","android")
builder.addFormDataPart("country_code",Constant.COUNTRY_CODE)
builder.addFormDataPart("email",signUpBean.email)
builder.addFormDataPart("mobile",signUpBean.phoneNumber)
builder.addFormDataPart("first_name",signUpBean.firstName)
builder.addFormDataPart("last_name",signUpBean.lastName)
builder.addFormDataPart("gender",signUpBean.gender)
builder.addFormDataPart("dob",signUpBean.dob)
builder.addFormDataPart("city",signUpBean.city)
builder.addFormDataPart("bike_type_id","1")
builder.addFormDataPart("bike_model",signUpBean.mfg)
builder.addFormDataPart("bike_manufacturer",signUpBean.mfg)
builder.addFormDataPart("reg_year",signUpBean.mfgYear)
builder.addFormDataPart("liecense_plate",signUpBean.licencePlateNo)
builder.addFormDataPart("bank_ac_name",signUpBean.bnkHolderName)
builder.addFormDataPart("bank_ac_number",signUpBean.bnkAccountNumber)
builder.addFormDataPart("bank_name",signUpBean.bnkName)
builder.addFormDataPart("bank_ifsc_code",signUpBean.ifscCode)
builder.addFormDataPart(
"profile_pic",
"profile" + ".jpg",
RequestBody.create(MediaType.parse("image/*"), file_profile!!)
)
builder.addFormDataPart(
"provider_documents[0][document]",
"1" + ".jpg",
RequestBody.create(MediaType.parse("image/*"), file_profile!!)
)
builder.addFormDataPart("provider_documents[0][document_id]","1")
builder.addFormDataPart("provider_documents[0][unique_id]","1")
builder.addFormDataPart("provider_documents[0][exprice_at]","2010-12-12")
val requestBody = builder.build()
observable = apiInterface.signUp2(requestBody)
I have tried many solutions but unable to post an image array with their data.
When i remove provider_documents from addFormDataPart it works fine.
// #Multipart
#POST(URLHelper.register)
fun signUp2(#Body builder: RequestBody ): Observable<Registration>
How can I send Providers_document array and it is working fine on Postman.
post this type of data from retrofit
val partMap = HashMap<String, RequestBody>()
partMap.put("device_id", createPartFromString(device_UDID));
partMap.put("device_token",createPartFromString(device_token))
partMap.put("device_type",createPartFromString("android"))
partMap.put("country_code",createPartFromString(Constant.COUNTRY_CODE))
partMap.put("email",createPartFromString(signUpBean.email))
partMap.put("mobile",createPartFromString(signUpBean.phoneNumber))
partMap.put("first_name",createPartFromString(signUpBean.firstName))
partMap.put("last_name",createPartFromString(signUpBean.lastName))
partMap.put("gender",createPartFromString(signUpBean.gender))
partMap.put("dob",createPartFromString(signUpBean.dob))
partMap.put("city",createPartFromString(signUpBean.city))
partMap.put("bike_type_id",createPartFromString("1"))
partMap.put("bike_model",createPartFromString(signUpBean.mfg))
partMap.put("bike_manufacturer",createPartFromString(signUpBean.mfg))
partMap.put("reg_year",createPartFromString(signUpBean.mfgYear))
partMap.put("liecense_plate",createPartFromString(signUpBean.licencePlateNo))
partMap.put("bank_ac_name",createPartFromString(signUpBean.bnkHolderName))
partMap.put("bank_ac_number",createPartFromString(signUpBean.bnkAccountNumber))
partMap.put("bank_name",createPartFromString(signUpBean.bnkName))
partMap.put("bank_ifsc_code",createPartFromString(signUpBean.ifscCode))
partMap.put(
"provider_documents["+0+"][document_id]",
createPartFromString(signUpBean.ifscCode)
)
partMap.put(
"provider_documents["+0+"][unique_id]",
createPartFromString(signUpBean.ifscCode)
)
partMap.put(
"provider_documents["+0+"][exprice_at]",createPartFromString(signUpBean.dob)
)
val ImageMap = HashMap<String, MultipartBody.Part>()
ImageMap.put("profile_pic", prepareFilePart("12", file_profile!!));
ImageMap.put("provider_documents["+0+"][document]", prepareFilePart("1", file_profile!!));
Request Api
#Multipart
#POST(URLHelper.register)
fun signUp3(
#PartMap photo: HashMap<String,
RequestBody>,
#PartMap ImageMap:HashMap<MultipartBody.Part>,
): Observable<Registration>
Dummy api interface.
public interface ApiInterface {
#Multipart
#POST(URLHelper.register)
Call<ModelProp> signUp2(#Part List<MultipartBody.Part> photos,
#PartMap Map<String, RequestBody> map;
}
Now create data to post like this.
Map<String, RequestBody> partMap = new HashMap<>();
List<MultipartBody.Part> images = new ArrayList<>();
partMap.put("device_id", createPartFromString(deviceId)); // add data which are common for all images like device_id, device_token, device_type etc.
..
..
for (int i=0; i < upFileList.size(); i++){
images.add(prepareFilePart("provider_documents["+i+"][document]", imageFile));
partMap.add("provider_documents["+i+"][expires_at]", createPartFromString(expiry)); // add image specific data.
...
..
}
...
..
observable = apiInterface.signUp2(images, partMap).
createPartFromString method
public RequestBody createPartFromString(String string) {
return RequestBody.create(MultipartBody.FORM, string);
}
prepareFilePart method
private MultipartBody.Part prepareFilePart(String partName, File file){
RequestBody requestBody = RequestBody.create(MediaType.parse("image/*"), file);
return MultipartBody.Part.createFormData(partName, file.getName(),requestBody);
}
Use it Like this:-
// #Multipart
#POST(URLHelper.register)
fun signUp2(#Part builder: MultipartBody ): Observable<Registration>
Updated :-
private void uploadToServer(String filePath) {
showProgressDialog();
Retrofit retrofit = RetrofitClient.getRetrofitClient(this);
ApiInterface uploadAPIs = retrofit.create(ApiInterface.class);
File file = new File(filePath);
//compressor.setDestinationDirectoryPath()
RequestBody fileReqBody = RequestBody.create(MediaType.parse("image/*"), file);
MultipartBody.Part part = MultipartBody.Part.createFormData("fileUpload", file.getName(), fileReqBody);
//RequestBody description = RequestBody.create(MediaType.parse("text/plain"), "image-type");
RequestBody imgNameReqBody = RequestBody.create(MediaType.parse("multipart/form-data"), "B2B_" + System.nanoTime());
uploadAPIs.uploadImage(imgNameReqBody, part).enqueue(new Callback<UploadImageRespose>() {
#Override
public void onResponse(#NonNull Call<UploadImageRespose> call, #NonNull retrofit2.Response<UploadImageRespose> response) {
if (response.isSuccessful() && response.body() != null) {
if (response.body().getCODE().equalsIgnoreCase("SUCCESS")) {
Toast.makeText(Activity.this, "Profile Image Upload Succesfully", Toast.LENGTH_SHORT).show();
} else {
hideProgressDialog();
Toast.makeText(Activity.this, "Some Error occurred, try again", Toast.LENGTH_SHORT).show();
}
} else {
hideProgressDialog();
}
}
#Override
public void onFailure(#NonNull Call<UploadImageRespose> call, #NonNull Throwable t) {
Timber.d(TAG, t.getMessage());
hideProgressDialog();
Toast.makeText(Activity.this, "Some Error occurred, try again", Toast.LENGTH_SHORT).show();
}
});
}
add below method in your interface:-
#Multipart
#POST("Your Path Here")
Call<UploadImageRespose> uploadImage(#Part("img_name") RequestBody img_name,
#Part MultipartBody.Part file);
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
}
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. :)