I have an app that should upload the following parameters
and here I have my code
#POST("task")
Call<ResponsetTask> API_Task(#Header("Authorization") String key, #Body RequestBody body);
[3
and
private void Analizar() {
File file=new File(path);
RequestBody requestBody =RequestBody.create(MediaType.parse("image/jpg"),file);
MultipartBody.Builder builder = new MultipartBody.Builder();
builder.setType(MultipartBody.FORM);
builder.addFormDataPart("message", Constantes.MESSAGE);
builder.addFormDataPart("filecomment", Constantes.FILECOMMENT);
builder.addFormDataPart("api_token", Constantes.api_token);
builder.addFormDataPart("user_id", Integer.toString(Constantes.id));
builder.addFormDataPart("image","image.jpg",requestBody);
MultipartBody body = builder.build();
Call<ResponsetTask>call=conexion2.API_Task(Constantes.AUTH,body);
call.enqueue(new Callback<ResponsetTask>() {
#Override
public void onResponse(Call<ResponsetTask> call, Response<ResponsetTask> response) {
if(response.isSuccessful()){
Constantes.api_task=response.body().getTaskId();
}
}
#Override
public void onFailure(Call<ResponsetTask> call, Throwable t) {
}
});
}
The problem is that the post does not work and does not tell me why I have a breakpoint in my code the BodyRequest is built but when it comes to the call it simply jumps to the end that is to say the onResponse () and the onFailure () skip the code seems work and the app does not hang or give Exception
I appreciate any help friends
This issue is that you are trying to pass data with multipart, Its an easy fix
Add this library
implementation "com.squareup.retrofit2:converter-scalars:$retrofit_version"
and this convertor factory
.addConverterFactory(ScalarsConverterFactory.create()) in your retrofit builder
.sample code is given below
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.client(httpClient.build())
.build();
Related
so basically am using retrofit to get data from an api called calorieNinja and for some reason i keep getting an unsuccessful response
here is the retrofit code :
retrofit = new Retrofit.Builder().baseUrl("https://api.calorieninjas.com/v1/")
.addConverterFactory(GsonConverterFactory.create())
.build();
ApiCalorieNinjas apiCalorieNinjas = retrofit.create(ApiCalorieNinjas.class);
Call<MealCalories> call = apiCalorieNinjas.getMeal("nutrition?query= 5 eggs");
call.enqueue(new Callback<MealCalories>() {
#Override
public void onResponse(Call<MealCalories> call, Response<MealCalories> response) {
if(!response.isSuccessful()){
Toast.makeText(getContext(),"Not Found",Toast.LENGTH_SHORT).show();
return;
}
mealEaten = response.body();
Meal meal1 = new Meal(mealEaten.getName(),mealEaten.getCalories(),mealEaten.getProtein_g(),mealEaten.getCarbohydrates_total_g());
mealViewModel.insertMeal(meal1);
}
#Override
public void onFailure(Call<MealCalories> call, Throwable t) {
}
});
}
});
btw am using 2 different types of meal objects because one is responsible of getting the data from the api and one is used as an entity for Room databse and they dont have the same parameters so instead of just adding #Ignore i decided to use two different objects while i try fixing this problem.
and here is the interface of it :
public interface ApiCalorieNinjas {
#Headers("X-Api-Key: PiQfBb0CZy2GfOZWjWyj6Tg==EdGjoESjqxQh1q4M")
#GET("{meal}")
public Call<MealCalories> getMeal(#Path("meal") String meal);
the api key isnt real!
if additional code is needed please let me know!
Try to add an interceptor so you can see all calls logs (headers, body, URLs, etc...) and see what it's the error that the API is sending.
Add OkHtpp to your grade dependencies:
implementation "com.squareup.okhttp3:okhttp:5.0.0-alpha.2"
implementation "com.squareup.okhttp3:logging-interceptor:5.0.0-alpha.2"
And after that, when you create your Retrofit instance, add the interceptor, should look something like this:
val httpClient = OkHttpClient.Builder()
val interceptor = HttpLoggingInterceptor()
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY)
httpClient.addInterceptor(interceptor)
httpClient.addInterceptor(Interceptor { chain: Interceptor.Chain ->
val original: Request = chain.request()
val request: Request = original.newBuilder()
.header("Content-Type", "application/json")
.method(original.method, original.body)
.build()
chain.proceed(request)
})
val okHttpClient = httpClient.build()
val retrofit = Retrofit.Builder()
.baseUrl("https://api.calorieninjas.com/v1/")
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.build()
I want to a upload file on my server and I've decided to try OKHTTP instead of my current method which is based on android own HTTP implementation and AsyncTask.
Anyway, I used OKHTTP and its asynchronous implementation (from its own recipes) but it returns an empty message (the request code is ok, the message is empty) in both GET and POST methods.
Did I implement it wrong or is there anything else remained that I did not considered? In the meantime, I couldn't find a similar case except this which says used AsyncTask.
Here's the code:
Request request;
Response response;
private final OkHttpClient client = new OkHttpClient();
private static final String postman_url = "https://postman-echo.com/get?foo1=bar1&foo2=bar2";
String message_body;
public void Get_Synchronous() throws IOException
{
request = new Request.Builder()
.url(postman_url)
.build();
Call call = client.newCall(request);
response = call.execute();
message_body = response.toString();
//assertThat(response.code(), equalTo(200));
}
public void Get_Asynchronous()
{
request = new Request.Builder()
.url(postman_url)
.build();
Call call = client.newCall(request);
call.enqueue(new Callback() {
public void onResponse(Call call, Response response)
throws IOException
{
message_body = response.toString();
}
public void onFailure(Call call, IOException e)
{
}
});
}
Edit:
I catch the log on response:
onResponse: Response{protocol=h2, code=200, message=, url=https://postman-echo.com/get?foo1=bar1&foo2=bar2}
OK, for anyone who wants to receive an string from a call, response and response.messgage() don't provide that. To catch the response from your provider, you just need to call response.body().string() inside onResponse which returns the message inside your request.
But after all, Retrofit is a better choice if you want to receive a JSON file using
.addConverterFactory(GsonConverterFactory.create(gson)).
If you still want to receive an string just use .addConverterFactory(ScalarsConverterFactory.create()) as explained here.
I know there are a lot of threads regarding this and i did go through them and also looked into the same Retrofit POST example,but i'm not sure what am i doing wrong in this,lemme know if any
#Multipart
#POST("api/customerdetail")
Call<Array> addUser(#Part("CustomerName") String CustomerName, #Part("CustomerId") String CustomerId, #Part("UserId") String UserId, #Part("VehicleCompanyName") String VehicleCompanyName, #Part("VehicleModelType")String VehicleModelType, #Part("VehicleNumber")String VehicleNumber, #Part("Location")String Location);
//METHOD USED TO CALL
private void simpleMethod() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://endpoint.net/")
.addConverterFactory(GsonConverterFactory.create())
.build();
GetDataService service = retrofit.create(GetDataService.class);
Call<Array> arrayListCall = service.addUser("Peter Jenkins", UUID.randomUUID().toString(),"user2","AUDI","R3","BVZ-009","-55,-93.23"); arrayListCall.enqueue(new Callback<Array>() {
#Override
public void onResponse(Call<Array> call, Response<Array> response) {
Log.e("RESPONSE",response.toString());
}
#Override
public void onFailure(Call<Array> call, Throwable t) {
Log.e("ERROR",t.toString());
} }); }
Works like a Charm in Postman,and uploading an image is not necessary,atleast from the api end
Any inputs would be deeply appreciated
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.
I am using OAuth and I need to put the OAuth token in my header every time I make a request. I see the #Header annotation, but is there a way to make it parameterized so i can pass in at run time?
Here is the concept
#Header({Authorization:'OAuth {var}', api_version={var} })
Can you pass them in at Runtime?
#GET("/users")
void getUsers(
#Header("Authorization") String auth,
#Header("X-Api-Version") String version,
Callback<User> callback
)
Besides using #Header parameter, I'd rather use RequestInterceptor to update all your request without changing your interface. Using something like:
RestAdapter.Builder builder = new RestAdapter.Builder()
.setRequestInterceptor(new RequestInterceptor() {
#Override
public void intercept(RequestFacade request) {
request.addHeader("Accept", "application/json;versions=1");
if (isUserLoggedIn()) {
request.addHeader("Authorization", getToken());
}
}
});
p/s : If you are using Retrofit2, you should use Interceptor instead of RequestInterceptor
Since RequestInterceptor is not longer available in Retrofit 2.0
Yes, you can pass them in runtime. As a matter of fact, pretty much exactly as you typed it out. This would be in your API interface class, named say SecretApiInterface.java
public interface SecretApiInterface {
#GET("/secret_things")
SecretThing.List getSecretThings(#Header("Authorization") String token)
}
Then you pass the parameters to this interface from your request, something along those lines: (this file would be for example SecretThingRequest.java)
public class SecretThingRequest extends RetrofitSpiceRequest<SecretThing.List, SecretApiInteface>{
private String token;
public SecretThingRequest(String token) {
super(SecretThing.List.class, SecretApiInterface.class);
this.token = token;
}
#Override
public SecretThing.List loadDataFromNetwork() {
SecretApiInterface service = getService();
return service.getSecretThings(Somehow.Magically.getToken());
}
}
Where Somehow.Magically.getToken() is a method call that returns a token, it is up to you where and how you define it.
You can of course have more than one #Header("Blah") String blah annotations in the interface implementation, as in your case!
I found it confusing too, the documentation clearly says it replaces the header, but it DOESN'T!
It is in fact added as with #Headers("hardcoded_string_of_liited_use") annotation
Hope this helps ;)
The accepted answer is for an older version of Retrofit. For future viewers the way to do this with Retrofit 2.0 is using a custom OkHttp client:
OkHttpClient httpClient = new OkHttpClient.Builder()
.addInterceptor(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Builder ongoing = chain.request().newBuilder();
ongoing.addHeader("Accept", "application/json;versions=1");
if (isUserLoggedIn()) {
ongoing.addHeader("Authorization", getToken());
}
return chain.proceed(ongoing.build());
}
})
.build();
Retrofit retrofit = new Retrofit.Builder()
// ... extra config
.client(httpClient)
.build();
Hope it helps someone. :)
Retrofit 2.3.0
OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder();
okHttpClientBuilder
.addInterceptor(new Interceptor() {
#Override
public okhttp3.Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Request.Builder newRequest = request.newBuilder().header("Authorization", accessToken);
return chain.proceed(newRequest.build());
}
});
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(GithubService.BASE_URL)
.client(okHttpClientBuilder.build())
.addConverterFactory(GsonConverterFactory.create())
.build();
I am using this to connect to GitHub.