Using Retrofit i dont know how to pass array of Values. My request look like this
{
type: integer,
id: string,
request: {
country: [ {
C-id: string,
C-name: string,
pin: string },
],
}
}
I tried like this but i dont have any responses,
#FormUrlEncoded
#POST(“/sam”)
void multi(#Field("type") int type, #Field("id") String id, #Field("request") ArrayList<Process> processResponses, Callback<Multiplex> cb);
Please help me to find solution
Create POJO describing your request and use the #Body field in retrofit to send the request.
#POST("/sam")
void multi(#Body MyRequest requestObject, Callback<Multiplex> cb);
Try this,
Set the values in your model class:
#POST(“/sam”)
void multi(#Body ModelClass modelClass, Callback<Multiplex> cb);
Related
I am using retrofit2 for network calls in my project. For a post method I need to pass request body data. So decided to use #Body annotation. This converts the given Gson.JsonObject to Array like below mentioned.
Retrofit dependencies used
//retrofit
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.squareup.okhttp3:logging-interceptor:4.7.2'
Expected
{
"key1": "value1",
"key2": "value2",
"key3": value3
}
But got converted like
[{
"key1": "value1",
"key2": "value2",
"key3": value3
}]
This is my API service call
#Headers("Content-Type: application/json")
#POST("Account/LoginAsync")
fun doLogin(#Body payLoad: JsonObject): Call<JsonObject>
And data class is
data class LoginRequest(
val email: String,
val password: String,
val rememberMe: Boolean
)
Internally what I am doing is
From the specified values in LoginRequest generating org.json.JSONObject like below
private fun generateLoginPayload(
email: String,
password: String,
rememberMe: Boolean
): JSONObject {
return JSONObject().apply {
put(LOGIN_EMAIL, email)
put(LOGIN_PASSWORD, password)
put(LOGIN_REMEMBER_ME, rememberMe)
}
}
And then
val payload = generateLoginPayload(email, password, rememberMe)
val requestCall = ApiService.create()
.doLogin(JsonParser().parse(payload.toString()) as JsonObject)
After enqueuing the request call got error response as 400 (bad request).
I have checked from the debug values.
What is the possible reason for it ?
Solution 1
If you're trying to send a json payload containing the email, password, and rememberMe option to the Account/LoginAsync endpoint you don't need the generateLoginPayload function.
First, refactor your API service function to something like this:
#Headers("Content-Type: application/json")
#POST("Account/LoginAsync")
fun doLogin(#Body payLoad: LoginRequest): Call<JSONObject>
Then update the payload
val payload = LoginRequest(email, password, rememberMe)
val requestCall = ApiService.create().doLogin(payload)
Solution 2
If you really want to use the JSONObject object in the request body there's no need to convert the payload object to a string, only to later use your JsonParser to convert it back to JSONObject. Just update the last part of the code to:
val payload = generateLoginPayload(email, password, rememberMe)
val requestCall = ApiService.create().doLogin(payload)
I'm not familiar with the JsonParser object. If it's a custom class, please also include the body of the parse method so we can inspect it (if the above solutions don't work).
I'm trying to post some data with retrofit 2 but I'm gettins some problems... and don't find any example like this...
This is the body that I have to send:
{
"birthday": "12-01-1987",
"name": bob,
"activity": {
"activity_preferences": {
"user_subjects": [4,7,8],
"user_allergies": [1,6,10],
}
}
}
This is my data class:
data class GenericFormDataEntity(
var birthday: String,
var name: String,
#SerializedName("activity")
var food: ActivityEntity?
)
data class ActivityEntity(#SerializedName("activity_preferences")val activityPreferences: ActivityPreferencesEntity)
data class ActivityPreferencesEntity(#SerializedName("user_Subjects")var userSubjects:List<Int>?,#SerializedName("user_allergies")var userAllergies: List<Int>?)
This is the method that I'm trying to build the json:
fun getUserFormEntity(): String{
val paramObject = JSONObject()
paramObject.put("birthday", birthday)
paramObject.put("name", name)
paramObject.put("activity", getActivityEntity())
return paramObject.toString()
}
private fun getActivityEntity(): ActivityEntity{
return ActivityEntity(ActivityPreferencesEntity(selectedSubjectList, selecteAllergiesList))
}
And this is the json that is returning me:
{\"birthday\":\"23-12-2019\",\"name\":Bob,"activity\":\"ActivityEntity(activity_preferences=ActivityPreferencesEntity(user_Subjects=[4,7,8], user_allergies=[1,6,10])"}"
My question is, how can I get the correct json that I have to send as a body:
#Headers("Accept: application/json")
#POST("xxxxxxxx")
suspend fun saveUserData(#Body userFormData: String)
You need to stringify getActivityEntity using Gson.
Gson.toJson(getActivityEntity())
Also, from your API I infer that you are using retrofit why not pass along the entire instance of GenericFormDataEntity as the body for your API.
For enabling this you need to follow by adding GsonConverterFactory.create(gson) to your retrofit.
Retrofit.Builder()
.baseUrl(url)
.addConverterFactory(GsonConverterFactory.create(gson))
.callFactory(okHttpClient)
.build()
I am creating a retrofit get request where i need to pass a data base query and some spacial character like '$' in URL in kotlin. But I am getting error.
java.lang.IllegalArgumentException: URL query string must not have replace block. For dynamic query parameters use #Query.
This is URL which I am using in postman but cant in retrofil
https://someURL.com?customParam=true&pageSize=100&query=$filter=(drivercell eq'1111111119')$orderby=creationTimedesc&withTotalPages=true
This is the code of calling retrofit method
val restServiceModel = DRestServiceModel.create()
val model = restServiceModel.getTripsData("Basic bWs6SU9UMTIzNCM=", "application/json", "\$filter=(drivercell%20eq'1111111119')")
This is method
#GET("inventory/managedObjects?customParam=true&pageSize=100&{query}\$orderby=creationTimedesc&withTotalPages=true")
fun getTripsData(#Header("Authorization") token: String, #Header("Content-Type") contentType: String, #Query("query", encoded = true) query : String): Single<TripsResponseModel>
Please help me.
Problem is you are trying to put Path param in a middle of a query while supplying it via another Query. You should rework your request. Try something like:
#GET("inventory/managedObjects")
fun getTripsData(#Header("Authorization") token: String,
#Header("Content-Type") contentType: String,
#Query("customParam") customParam: Boolean?,
#Query("pageSize") pageSize: Int?,
#Query("query", encoded = true) query: String,
#Query("withTotalPages") withTotalPages: Boolean?): Single<TripsResponseModel>
And use it like:
val model = restServiceModel.getTripsData("Basic bWs6SU9UMTIzNCM=", "application/json", true, 100, "your query_goes here", true)
This way should it work.
I have a APIService class for request URL.
I want to set "/products?page=1" to annotation #GET but I want that I can change parameter and value.
this is my APIService class:
public interface APIService {
#GET("products?{parameter}={value}")
Call<List<DataModelProducts>> getProducts(#Path("parameter") String parameter,#Path("value") String value);
}
How can I change "parameter" and "value" in my app ?
I believe it will be sufficient to use #Query Annotation like below :
#GET("group/{id}/users/list")
Call<List<User>> groupList(#Path("id") int groupId, #Query("sort") String sort);
it will create a request like: .../users/list?sort=desc
or if you want to be able to change both sort/desc as for the sample request above you can use #QueryMap:
#GET("group/{id}/users/list")
Call<List<User>> groupList(#Path("id") int groupId, #QueryMap Map<String, String> options);
this will create a request like: .../users/list?key=value
where the key/value are specified in the Map<String, String> options
for more information on different Annotations for Retrofit2, you can visit
Retrofit API Declarations
Your page number is passed as a query parameter. To pass query parameter in retrofit, you need to pass it like:
public interface APIService {
#GET("products")
Call<List<DataModelProducts>> getProducts(#Query("page") String pagerNumber);
}
EDIT: to use a query map:
public interface APIService {
#GET("products") Call<List<DataModelProducts>> getProducts(#QueryMap HashMap queryParams); }
Here, whatever you add as the key will replce "page" and value will be added.
for eg if hash map has:
queryParams.put("something", "value");..
you request will be like:
url?something=value
Try this
public interface APIService {
#FormUrlEncoded
#GET("/products?page=1")
Call<List<DataModelProducts>> getProducts(#Field("parameter") String
parameter,#Field("value") String value);
}
I am trying to make POST request using the Retrofit 2. The request type is form-data NOT application/x-www-form-urlencoded.
I am only posting data not the files in the request and the response is in the form of JSON.
I have tried #FormUrlEncoded, #Multipart but it is not working.
I have tried following request
1. First Attempt
#FormUrlEncoded
#POST("XXXX")
Call<PlanResponse> getPlanName(#Field(Constants.ACTION_ID) String actionId, #Field(Constants.OFFER_CODE) String offerCode);
2. Second Attempt
#Headers({"Content-Type: multipart/form-data","Content-Type: text/plain"})
#FormUrlEncoded
#POST("XXXX")
Call<PlanResponse> getPlans(#Body #FieldMap(encoded = false) Map<String, String> data);
3. Third Attempt
#Headers("Content-Type: multipart/form-data")
#Multipart
#POST("XXXX")
Call<PlanResponse> myPlans(#Part(Constants.ACTION_ID) String actionId, #Part(Constants.OFFER_CODE) String offerCode);
I am only getting the body as null. It is working with the POSTMAN.
I have also search about form-data and application/x-www-form-urlencoded and found that if the data is binary then use form-data and if data is ASCII then use application/x-www-form-urlencoded
I am trying find Is form-data is not supported by the Retrofit?
POSTMAN request
Cache-Control: no-cache
Postman-Token: XXXXXXXXXXXX-XXXXXXXXXXXX-XXXXXXXXXXXX-XXXXXXXXXXXX-XXXXXXXXXXXX
Content-Type: multipart/form-data; boundary=---- WebKitFormBoundaryXXXXXXXXXXXX
----WebKitFormBoundaryXXXXXXXXXXXX
Content-Disposition: form-data; name="actionId"
1000
----WebKitFormBoundaryXXXXXXXXXXXX
Content-Disposition: form-data; name="offerCode"
MYCODE
----WebKitFormBoundaryXXXXXXXXXXXX
I can only add HTTP Generated code snipped from POSTMAN
Here's another Solution using request body:
RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("param1", param1)
.addFormDataPart("param2", param2)
.build();
apiInterface.somePostMethod(requestBody).enqueue(
//onResponse onFailure methods
);
here's my api inteface POST method
#POST("somePostMethod")
Call<ResponseBody> somePostMethod(#Body RequestBody body);
Hope it helps.
In retrofit 2.0 to perform POST request like above, you should use RequestBody type for your parameter like this.
#Multipart
#POST("XXXX")
Call<PlanResponse> myPlans(#Part(Constants.ACTION_ID) RequestBody actionId, #Part(Constants.OFFER_CODE) RequestBody offerCode);
And here how to get requestBody from String.
String somevalue = "somevalue";
RequestBody body = RequestBody.create(MediaType.parse("text/plain"), somevalue);
I wanted to pass an array of ids to an existing request.
I tried several variants from here, Retrofit - Send request body as array or number, How to send PUT request with retrofit string and array list of model I need to use URL encoded, but they didn't work. Then I tried android retrofit send array as x-www-form-urlencoded.
I added [] to a list parameter and List to it's type:
#FormUrlEncoded
#POST("your_request/")
fun sendIds(
#Field("token") token: String,
#Field("city_id") cityId: Int?,
#Field("description") description: String,
#Field("ids[]") ids: List<Int>? // Add '[]' here.
): Deferred<YourResponse>
Then called it as usual (with Kotlin coroutines):
api.sendIds("f0123abc", null, "description", listOf(1, 2, 3)).await()
See also Is it possible to send an array with the Postman Chrome extension? to understand how it looks like in Postman.
form-data is supported for sure.
I will make you clear using an example of typical signup process.
First of all add a header
#FormUrlEncoded
in your user client.
Use
#FieldMap
instead of direct objects. So your user-client code will something like this
#POST("signup/")
#FormUrlEncoded
Call<ResponseModel> signup(#FieldMap Map<String,String> params);
Now in your main activity, make a Hashmap all of your data like this,
Map<String,String> params = new HashMap<String, String>();
params.put("fullname", fullname);
params.put("city", city);
params.put("state",state);
params.put("address",address);
params.put("email",email);
params.put("password1", password1);
params.put("password2", password2);
Now simple pass this hashmap into the method like this
Call<ResponseModel> call = service.signup(params);
call.enqueue(new Callback<ResponseModel>() {
#Override
public void onResponse(Call<ResponseModel> call, Response<ResponseModel> response) {
if (response.isSuccessful()) {
Toast.makeText(SignUp.this,response.body.getData,Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(SignUp.this, "Error : ", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onFailure(Call<ResponseModel> call, Throwable t) {
t.printStackTrace();
Toast.makeText(SignUp.this, "Server Unavailable : "+t.toString(), Toast.LENGTH_SHORT).show();
}
});
Here's another Solution using the request body form-data in Kotlin. This solution work for me in Kotlin.
val request = ServiceBuilder.buildService(TmdbEndpoints::class.java)
val requestBody: RequestBody = MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("email", "abc#gmail.com")
.addFormDataPart("password", "admin")
.addFormDataPart("push_token", "token")
.addFormDataPart("device_id", "1112222")
.addFormDataPart("platform", "android")
.addFormDataPart("device_name", "my device")
.addFormDataPart("version", "1.2")
.build()
val call = request.userFigLogin(requestBody)
call.enqueue(object : Callback<LoginResult> {
override fun onFailure(call: Call<LoginResult>, t: Throwable) { }
override fun onResponse(call: Call<LoginResult>,
response: retrofit2.Response<LoginResult>) { }
})
You should use RequestBody type for your parameter like this.
#POST("api/login")
fun userFigLogin(#Body body: RequestBody): Call<LoginResult>
For Kotlin, This is another way of doing it. For api that do not accept FormUrEncoded data.
fun login(email: String, password: String, grantType: String):
Single<TokenModel> {
var userNameB:RequestBody=
email.toRequestBody(email.toMediaTypeOrNull())
var passwordB: RequestBody =
password.toRequestBody(password.toMediaTypeOrNull())
var grantTypeB: RequestBody =
grantType.toRequestBody(grantType.toMediaTypeOrNull())
return userApi.loginUSer(userNameB,passwordB,grantTypeB)
.map { TokenModel(it.accessToken, it.refreshToken) }
}
Then.
#Multipart
#POST("auth/token/")
fun loginUSer(
#Part("username") request: RequestBody,
#Part("password") passwordB: RequestBody,
#Part("grant_type") grantTypeB: RequestBody
): Single<Token>
just remove this from header
defaultProperties["Content-Type"] = "application/json"
I think this can help you
#Multipart
#Headers( "Content-Type: application/x-www-form-urlencoded")
#POST("api/register")
fun postRegister(
#Part("authtype") authtype: String,
#Part("channel")channel : String,
#Part("children")children : List<String>,
#Part("names") names: List<String>,
#Part("email") email: String,
#Part("password")password : String,
#Part("name") name: String,
#Part("timezone") timezone: Int,
#Part("timezone_name")timezone_name : String,
#Part("token_device")token_device : String,
#Part("imageData") imageData: String,
#Part("mimeType") mimeType: String,
#Part("extension") extension: String,
): Call<ResponseBase>