Retrofit: Only #Query is working but #Field is not working - android

I am tried to insert the data using #Field and #Body with #POST but it generates "500 internal server error" and same code I tried with #GET and #Query then it works correct and data inserted successfully.
So is there any way to insert data using #Body or #Field to my asp.net web-site using web service web method.
Using #Body
#POST("/EducationApi.asmx/addEducationAPI")
public void addEducation(#Body Education education, Callback<Education> callback);
'''
Using #Field
'''
#FormUrlEncoded
#POST("/EducationApi.asmx/insertEducationAPI/")
public void insertEducationDetail(#Field("user_id") int user_id, #Field("degree_name") String degree_name, #Field("institute_name") String institute_name, #Field("board_university_name") String board_university_name, #Field("year_of_passing") int year_of_passing, #Field("percentage_cgpa") float percentage_cgpa, #Field("specialization") String specialization, Callback<Education> callback);
using #Query (This works proper)
#GET("/EducationApi.asmx/insertEducationAPI")
public void insertEducation(#Query("user_id") int user_id,#Query("degree_name") String degree_name, #Query("institute_name") String institute_name, #Query("board_university_name") String board_university_name,#Query("year_of_passing") int year_of_passing,#Query("percentage_cgpa") float percentage_cgpa,#Query("specialization") String specialization, Callback<Education> callback);
I want to use #Post to insert the record to my database

#FormUrlEncoded
#POST("/EducationApi.asmx/insertEducationAPI/")
public void insertEducationDetail(#Field("user_id") int user_id, #Field("degree_name") String degree_name, #Field("institute_name") String institute_name, #Field("board_university_name") String board_university_name, #Field("year_of_passing") int year_of_passing, #Field("percentage_cgpa") float percentage_cgpa, #Field("specialization") String specialization, Callback<Education> callback);
I have done a silly mistake with the above code. That's why it is not working so change the above code to below code
#FormUrlEncoded
#POST("/EducationApi.asmx/insertEducationAPI")
public void insertEducationDetail(#Field("user_id") int user_id, #Field("degree_name") String degree_name, #Field("institute_name") String institute_name, #Field("board_university_name") String board_university_name, #Field("year_of_passing") int year_of_passing, #Field("percentage_cgpa") float percentage_cgpa, #Field("specialization") String specialization, Callback<Education> callback);

Yes It is Possible to Send Data With Body. Inside Body You can send #Field and #query or Multi-part Data as per Your Choice.
See Below Code Here I create On Class which merge #Field and Multi-part data for image upload and send all this data through Body.
public void addConactList(String name, String vessel, String email, String phone, String country, String note, String selectedfilename, ByteArrayOutputStream bos, String bvalue, String pvalue, String intrested) {
RetroFitService retroFitService = RetrofitClient.getSalesLead();
MultipartBody.Builder builder = new MultipartBody.Builder().setType(MultipartBody.FORM);
builder.addFormDataPart(Const.Name, name)
.addFormDataPart(Const.Vessel, vessel)
.addFormDataPart(Const.Email, email)
.addFormDataPart(Const.Phone, phone)
.addFormDataPart(Const.Country, country)
.addFormDataPart(Const.Notes, note)
.addFormDataPart(Const.Photo, selectedfilename, RequestBody.create(MultipartBody.FORM, bos.toByteArray()))
.addFormDataPart(Const.Business, bvalue)
.addFormDataPart(Const.Probability, pvalue)
.addFormDataPart(Const.Interest, intrested);
RequestBody requestBody = builder.build();
try {
Call<ContactResponse> call = retroFitService.addCountryList(requestBody);
call.enqueue(new Callback<ContactResponse>() {
#Override
public void onResponse(Call<ContactResponse> call, Response<ContactResponse> response) {
ContactResponse msg = response.body();
Log.e(TAG, "onResponse: " + msg.toString());
listener.onAddContact();
}
#Override
public void onFailure(Call<ContactResponse> call, Throwable t) {
Log.e(TAG, "onFailure: " + t.toString());
listener.onAddContact();
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
Then after i call this class file Method from my activity using Below Code.
new AddContactDetails(context, this).addConactList(name, vessel, email, phone, country, note, selectedFileName, bos, bvalue, pvalue, intrested);
You Have to Post body method in Retrofit Service Class like below code.
#POST(Const.Add_Contact)
Call<ContactResponse> addCountryList(#Body RequestBody file);

Related

Android Studio - Using retrofit2 to get info from restdb

I'm trying to use Retrofit2 to create a GET petition for my Android app. I have followed a tutorial on how to create the code and it worked with a webpage that did not need any authentication. Then I tried to adapt the same code to my needs, but I can't get it right. Either I get a 401 error or I get a 500 error.
I want to reach this URL: http://adaptai-eea8.restdb.io/rest/usuarios
So my baseurl is http://adaptai-eea8.restdb.io/.
This is my function, which is in the MainActivity:
private void find(String codigo){
String apikey = "9dc3afb8b6087192d5e9e50c5f2cb44927be5";
Retrofit retrofit = new Retrofit.Builder().baseUrl("http://adaptai-eea8.restdb.io/")
.addConverterFactory(GsonConverterFactory.create()).build();
UsuarioAPI usuarioAPI = retrofit.create(UsuarioAPI.class);
Call<Usuario> call = usuarioAPI.find(codigo);
call.enqueue(new Callback<Usuario>() {
#Override
public void onResponse(Call<Usuario> call, Response<Usuario> response) {
try {
int a = 5;
if(response.isSuccessful()){
Usuario u = response.body();
textView.setText(u.getContra());
Log.d("Funciona", u.getContra());
}
}catch(Exception ex){
Toast.makeText(MainActivity.this, ex.getMessage(), Toast.LENGTH_SHORT);
}
}
#Override
public void onFailure(Call<Usuario> call, Throwable t) {
Toast.makeText(MainActivity.this, "Error de conexión", Toast.LENGTH_SHORT);
}
});
}
And this is the GET petition I am using:
#Headers({"User-Agent: my-restdb-app","Content-Type: application/x-www-form-urlencoded", "x-apikey: heregoestheapikey", "Accept: application/json", "cache-control: no-cache"})
//#FormUrlEncoded
#GET("rest/usuarios/")
//public Call<Usuario> find(#Query("nombre") String nombre);
Call<Usuario> find(#Query("nombre") String nombre);
There has to be something wrong with this code, and maybe it is related to sending the apikey as a header, i don't know. Can someone tell me where am I wrong? Thanks in advance.
If you want to pass the apiKey as header you need to pass it as a parameter like you can see in the docs
#Headers({"User-Agent: my-restdb-app","Content-Type: application/x-www-form-urlencoded", "Accept: application/json", "cache-control: no-cache"})
#GET("rest/usuarios/")
Call<Usuario> find(#Header("x-apikey") String apiKey, #Query("nombre") String nombre);
Additionally, are you sure about the rest of parameters? Like User-Agent being "my-restdb-app" and query param name being "nombre"

Retrofit call returning 400, cURL request working perfectly fine, syntax issue

I've tried making a retrofit call to an API endpoint, but it's returning a 400 error, however my curl request is working perfectly fine. I can't seem to spot the error, could someone double check my work to see where I made a mistake?
The curl call that works:
curl --request POST https://connect.squareupsandbox.com/v2/payments \
--header "Content-Type: application/json" \
--header "Authorization: Bearer accesstoken112233" \
--header "Accept: application/json" \
--data '{
"idempotency_key": "ab2a118d-53e2-47c6-88e2-8c48cb09bf9b",
"amount_money": {
"amount": 100,
"currency": "USD"},
"source_id": "cnon:CBASEITjGLBON1y5od2lsdxSPxQ"}'
My Retrofit call:
public interface IMakePayment {
#Headers({
"Accept: application/json",
"Content-Type: application/json",
"Authorization: Bearer accesstoken112233"
})
#POST(".")
Call<Void> listRepos(#Body DataDto dataDto);
}
DataDto class:
public class DataDto {
private String idempotency_key;
private String amount_money;
private String source_id;
public DataDto(String idempotency_key, String amount_money, String source_id) {
this.idempotency_key = idempotency_key;
this.amount_money = amount_money;
this.source_id = source_id;
}
}
And lastly making the retrofit call:
DataDto dataDto = new DataDto("ab2a118d-53e2-47c6-88e2-8c48cb09bf9b", "{\"amount\": 100, \"currency\": \"USD\"}", "cnon:CBASEITjGLBON1y5od2lsdxSPxQ");
RetrofitInterfaces.IMakePayment service = RetrofitClientInstance.getRetrofitInstance().create(RetrofitInterfaces.IMakePayment.class);
Call<Void> call = service.listRepos(dataDto);
call.enqueue(new Callback<Void>() {
#Override
public void onResponse(#NonNull Call<Void> call, #NonNull Response<Void> response) {
Log.d(TAG, "onResponse: " + response.toString());
}
#Override
public void onFailure(#NonNull Call<Void> call, #NonNull Throwable t) {
Log.d(TAG, "onFailure: Error: " + t);
}
});
Retrofit Instance:
public class RetrofitClientInstance {
private static Retrofit retrofit;
private static final String BASE_URL = "https://connect.squareupsandbox.com/v2/payments/";
public static Retrofit getRetrofitInstance() {
if (retrofit == null) {
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
Edit 1: Changing to second parameter to JSON Object
JSONObject jsonObject = new JSONObject();
try{
jsonObject.put("amount", 100);
jsonObject.put("currency", "USD");
}catch (Exception e){
Log.d(TAG, "onCreate: " + e);
}
DataDto dataDto = new DataDto("ab2a118d-53e2-47c6-88e2-8c48cb09bf9b", jsonObject, "cnon:CBASEITjGLBON1y5od2lsdxSPxQ");
First of all, let's see what 400 means
The HyperText Transfer Protocol (HTTP) 400 Bad Request response status
code indicates that the server cannot or will not process the request
due to something that is perceived to be a client error (e.g.,
malformed request syntax, invalid request message framing, or
deceptive request routing).
Now we are sure, the problem stands in our request (not server fault), most probably it is because you are trying to convert JSON in request (do not do this explicitly GSON will convert automatically)
Use interceptor to verify your outgoing network requests (Tell the result here)
you use #POST(".") which does not make sense, please understand BASE_URL is your server URL NOT MORE
The problem could be translating this post request
So a possible solution
Change base URL into "https://connect.squareupsandbox.com/"
Replace #POST(".") with #POST("v2/payments/")
PS. #NaveenNiraula mentioned right thing even though it did not help you, please follow his instruction, it is the correct way parsing data using GSON (make sure you include it and configure it correctly) converter
EDIT
I make it work (I eliminated 400 error code that is what you want as long as question title is concerned) partially which means I detect why 400 error was occurred and fixed it but unfortunately, I stuck the UNAUTHORIZED issue. The problem was relating to converting json and data type
data class DataDTO(
val idempotency_key: String,
val source_id: String,
val amount_money: MoneyAmount
)
data class MoneyAmount(
val amount: Int,
val currency: String
)
I gist all code here you can refer
You need two DTO classes as below:
public class Amount_money
{
private String amount;
private String currency;
public String getAmount ()
{
return amount;
}
public void setAmount (String amount)
{
this.amount = amount;
}
public String getCurrency ()
{
return currency;
}
public void setCurrency (String currency)
{
this.currency = currency;
}
#Override
public String toString()
{
return "ClassPojo [amount = "+amount+", currency = "+currency+"]";
}
}
And
public class DataDto
{
private String idempotency_key;
private Amount_money amount_money;
private String source_id;
public String getIdempotency_key ()
{
return idempotency_key;
}
public void setIdempotency_key (String idempotency_key)
{
this.idempotency_key = idempotency_key;
}
public Amount_money getAmount_money ()
{
return amount_money;
}
public void setAmount_money (Amount_money amount_money)
{
this.amount_money = amount_money;
}
public String getSource_id ()
{
return source_id;
}
public void setSource_id (String source_id)
{
this.source_id = source_id;
}
#Override
public String toString()
{
return "ClassPojo [idempotency_key = "+idempotency_key+", amount_money = "+amount_money+", source_id = "+source_id+"]";
}
}
You need to create object for each like under :
Amount_money am = new Amount_money();
am.setAmount("100");
am.setCurrency("USD");
DataDto dto = new DataDto();
dto.setIdempotency_key("your key");
dto.setsource_id("your id");
dto.setAmount_money(am);
RetrofitInterfaces.IMakePayment service = RetrofitClientInstance.getRetrofitInstance().create(RetrofitInterfaces.IMakePayment.class);
Call<Void> call = service.listRepos(dataDto);
// yo get the point follow along
Most likely the passed JSON structure is not serialized in the same format.
"amount_money": {
"amount": 100,
"currency": "USD"},
I would at first use for private String amount_money; a real DTO having the amount and currency fields. This should give progress. I'm not 100% sure how the underscore mapping of attributes looks like, but this is the next step.
Add logging to be able to see the passed data. A quick search reveals this tutorial: https://futurestud.io/tutorials/retrofit-2-log-requests-and-responses. When seeing the transmitted data it should be easy to compare the expected and sent data.
Please check your base url.
In your curl you have https://connect.squareupsandbox.com/v2/payments
But in the code you have
private static final String BASE_URL = "https://connect.squareupsandbox.com/v2/payments/";
There is extra / (slash) in the end. I've seen cases where it was the issue. Could be your problem :)

How to receive the data sent from client

I am trying to send data (POST request) from android app using retrofit2 library and receive it on the server which is written in nodejs (using express framework) but i am not able to retrieve the data which is sent from the the app.
I used retrofit with GsonConverterfactory and sent a POST request to "/temp" route.
Index.js (handles route requests):-
var express = require("express");
var bodyParser = require("body-parser");
var app = express();
app.use(bodyParser.urlencoded({extended:true}));
app.use('/public',express.static('public'));
app.post("/temp",function(req,res){
console.log(req.body);
obj = {
orgName : "Got the message ",
address : "on the server"
}
res.json(obj);
})
app.listen(8000,function(){
console.log("Server Started at port 8000");
})
Shop.java
package com.example.myapplication;
public class Shop {
private String orgName;
private String address;
public Shop(String orgName, String address) {
this.orgName = orgName;
this.address = address;
}
public String getOrgName() {
return orgName;
}
public String getAddress() {
return address;
}
}
ShopApi.java
package com.example.myapplication;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.POST;
public interface ShopApi {
#POST("temp")
Call<Shop> create(#Body Shop shop);
}
postData() - Method to post data from MainActivity.java
public void postData(View view){
String BASE_URL = "http://10.0.2.2:8000/";
String org = orgName.getText().toString();
String address = add.getText().toString();
//Toast.makeText(getApplicationContext(),org+" "+address,Toast.LENGTH_SHORT).show();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
ShopApi shopApi = retrofit.create(ShopApi.class);
Shop shop = new Shop(org,address);
Call<Shop> shopCall = shopApi.create(shop);
shopCall.enqueue(new Callback<Shop>() {
#Override
public void onResponse(Call<Shop> call, Response<Shop> response) {
if(!response.isSuccessful()){
Toast.makeText(getApplicationContext(),response.code(),Toast.LENGTH_LONG).show();
}
Shop shopResponse = response.body();
String content = shopResponse.getOrgName() + shopResponse.getAddress();
Toast.makeText(getApplicationContext(),content,Toast.LENGTH_SHORT).show();
}
#Override
public void onFailure(Call<Shop> call, Throwable t) {
Toast.makeText(getApplicationContext(),t.getMessage(),Toast.LENGTH_SHORT).show();
}
});
}
A json object is expected in the req.body which should be printed in terminal but this gets printed :-
Server Started at port 8000
{}
Please help me to retrieve data on sever.
I don't work in Node.js still I try to answer your question.
You're expecting a JSON object in server like below,
{
"orgName": "Organization name",
"address": "Organization address"
}
Okay, your Android part (Retrofit api interface) is correct. In run-time it produces the expected JSON object. But, in your server side you're accepting application/x-www-form-urlencoded instead of application/json data. Which is causing this issue IMO.
Just replace the following code from
app.use(bodyParser.urlencoded({extended:true}));
to
app.use(bodyParser.json());
And give it a try once!
body-parser doc

Anonymous upload to Imgur's API using Retrofit 2

I let my user select a picture in their gallery, save its Uri, set a title and description and wish to upload it anonymously using Imgur's API, with this endpoint using Retrofit 2.
So far, this is what I am doing with no success:
In my ImgurAPI interface:
#Multipart
#POST("image")
Call<BrowseData> postImage(
#Header("Authorization") String auth,
#Part MultipartBody.Part file,
#Query("image") String image,
#Query("album") String albumId,
#Query("type") String type,
#Query("title") String title,
#Query("description") String description
);
In my API handler:
public void uploadImage(Uri fileUri, String image, String album, String type,
String title, String description) {
// create upload service client (retrofit builder and such)
ImgurAPI service =
ServiceGenerator.createService(ImgurAPI.class);
File file = FileUtils.getFile(caller.getActivity(), fileUri);
// create RequestBody instance from file
RequestBody requestFile =
RequestBody.create(
MediaType.parse(caller.getActivity().getContentResolver().getType(fileUri)),
file
);
// MultipartBody.Part is used to send also the actual file name
MultipartBody.Part body =
MultipartBody.Part.createFormData("picture", file.getName(), requestFile);
// finally, execute the request
Call<BrowseData> call = service.postImage(clientId, body, image, album, type, title, description);
call.enqueue(new Callback<BrowseData>() {
#Override
public void onResponse(Call<BrowseData> call,
Response<BrowseData> response) {
Log.v("Upload", "success");
}
#Override
public void onFailure(Call<BrowseData> call, Throwable t) {
Log.e("Upload error:", t.getMessage());
}
});
}
That is called like such on a simple FAB click:
controller = new ImgurAPIHandler(this);
controller.uploadImage(chosenUri, encodedImage, "AlbumName", "base64", title, desc);
But upon executing the request, I get the following error:
Write error: ssl=0x9c531200: I/O error during system call, Broken pipe
Can somebody explain to me what I am doing wrong? (If you have sufficient information).

Trouble get special character in retrofit 2 and gson

I'm trying to get a json list from a web service.
This is the json string return by server :
[{"categoryName":"Política"},{"categoryName":"Economía"},{"categoryName":"Cultura"},{"categoryName":"Deportes"}
The problem is converting in to the POJO. The special characters (í) it's appear like "Pol�tica".
This is the retrofit call function :
#GET("categories")
public Call<List<CategoryPojo>> getCategorias(#Query("sitename") String site)
this is the callback function:
Call<List<CategoryPojo>> call = restservice.getApiService().getCategorias(medio);
try {
call.enqueue(new Callback<List<CategoryPojo>>() {
#Override
public void onResponse(Call<List<CategoryPojo>> call, Response<List<CategoryPojo>> response) {
List<CategoryPojo> categories = response.body();
if (listener != null)
listener.onDataLoaded(categories);
}
#Override
public void onFailure(Call<List<CategoryPojo>> call, Throwable throwable) {
Log.e("Retrofit Error", throwable.getMessage());
}
});
this is the POJO:
public class CategoryPojo implements Serializable{
public CategoryPojo() { }
#SerializedName("categoryName")
private String name;
public String getName()
{
return this.name;
}
}
The result of the request to the Web services, (output in browser) is :
[{"categoryName":"Política"},{"categoryName":"Economía"},{"categoryName":"Cultura"},{"categoryName":"Deportes"},{"categoryName":"Salud"},{"categoryName":"Ciencia y Tecnología"},{"categoryName":"Medio Ambiente"},{"categoryName":"Medios"},{"categoryName":"Militar e Inteligencia"},{"categoryName":"Sociedad"}]
So, the return json has a good encoding...i think that maybe is about the way retrofit read the response.
I'm using retrofit-2.0.2, gson-2.6.1, converter-gson-2.0.2, okhttp-3.2.0.
Any help? please
You should check Content-type in the response headers. Look for the charset value and try to change that on the backend side to application/josn;charset=UTF-8. That worked for me.

Categories

Resources