How to pass data base query in URL of get request retrofit? - android

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.

Related

How to send list of string to server in Android

In my application I want send some data to server and for this I used Retrofit library.
I should send data such as below:
{
"hours": ["22:05","19:57"]
}
I write below codes for Api services:
#POST("profile")
suspend fun postSubmitDrug(#Header("Authorization") token: String, #Body body: RequestBody):Response<ProfileData>
And write below codes info fragment for send data to server:
private lateinit var requestBody: RequestBody
var hourMinuteList = mutableListOf<String>()
val multiPart = MultipartBody.Builder().setType(MultipartBody.FORM).addFormDataPart("_method", "post")
multiPart.addFormDataPart("hours[]", parentActivity.hourMinuteList.toString())
requestBody = multiPart.build()
But send this list such as below:
{
"hours": [22:05,19:57]
}
How can I fix it and send list of string to server?
Use com.google.gson, and when you create your retrofitCLient call .addConverterFactory(create(GsonBuilder()))
create data model, ex:
data class RequestBody(
val hours: ArrayList<String>? = null
)
and just call your endpoint
#POST("profile")
suspend fun postSubmitDrug(#Header("Authorization") token: String, #Body body: RequestBody):Response<ProfileData>
and this is all, gson will automatically serialize your data to json

retrofit #Body converts the given body data as array

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).

How to pass data in url without Query in Retrofit

I am using Retrofit for API calls.. My API is like this https://test/update/123456789..
In this API need to pass "123456789" as value.. Can anyone help me to do this using Retrofit.. How can I pass this value w/o Query..
Thanks in Advance..:)
fun updatePriceTesting(#Query("device_id") deviceId: String, #Query("appId") appId: String, #Body RequestBody: RequestBody) : Deferred
Response>
To pass a value in retrofit you have to annotate it as #Query,or #Path,in case you dont want to use #Query,you can use #Path in the method parameter ,for example : if you want to send a value to your api , let us say
www.fb.com/post,to pass id of post to retrieve,we have to do it like that:
#Get("www.fb.com/post/{post_id}")
if your id is an int then you can use :
Call<Post> getPost( #Path("post_id") int postId);
but if it was an string :
Call<Post> getPost( #Path("post_id") String postId);
and then you can call this method :
yourApiServiceObj.getPost(thePostId);
As it's appears that this is not clear I will write it as answer
if your url will be like this update/123456789?appId=5452266 which is update/device_id?appId=5452266 then your function call will be
#FormUrlEncoded
#POST("update/{device_id}")
fun updatePriceTesting(#Path("device_id") deviceId: String, #Field("appId") appId: String, #Body RequestBody: RequestBody) : Deferred
if your url will be like this update/5452266?device_id=123456789 which is update/appId?device_id=123456789 then your function call will be
#FormUrlEncoded
#POST("update/{appId}")
fun updatePriceTesting(#Field("device_id") deviceId: String, #Path("appId") appId: String, #Body RequestBody: RequestBody) : Deferred
if your url will be like this update/123456789/5452266 which is update/device_id/appId then your function call will be
#FormUrlEncoded
#POST("update/{device_id}/{appId}")
fun updatePriceTesting(#Path("device_id") deviceId: String, #Path("appId") appId: String, #Body RequestBody: RequestBody) : Deferred

trying to put JSONObject inside #Field in POST Api but not working

#Headers("Accept: application/json")
#POST("/api/v1/search/filter")
#FormUrlEncoded fun searchFilter(#Field("leaf_id") leaf_id: Int,
#Field("lang") lang: String,
#Field("token") token: String,
#Field("ud_id") ud_id: String,
#Field("min_price") min_price: Float,
#Field("max") max: Float,
#Field("page") page: Int,
#Field("per_page") per_page: Int,
#Field("properties") properties:JSONObject): Observable<RespProductsInCatg>
here in the #Field("properties") I'm trying to send json object but getting failed response.
In Postman its returning proper response
Try to use a data class for parameters to be passed in properties field.
Then pass an object of that data class, and use #Body instead of #Field for properties.
Try creating whole request as an object and add the same as #Body param without using #Field values.
Something like
data class Request(var leaf_id:Int,
var lang: String,
.
.
.
var properties: List<Property>);
and
data class Property(var param1:Int, .... );
construct the Request Object and try adding just that as #Body param.

Retrofit 2 with only form-data

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>

Categories

Resources