I'm having trouble finding how to do a Retrofit #POST with a JSONObject.
interface AuthApi {
#Multipart
#POST("auth/login")
suspend fun userLogin(
#Body authResponse: JSONObject?
): Response<AuthResponse>
}
When sending I am getting an error:
E/UncaughtException: java.lang.IllegalArgumentException: #Body
parameters cannot be used with form or multi-part encoding.
I'm pretty sure I am not sending the JSONObject the right way, but I can't find a good guide to help me with this implementation in Kotlin.
I have tried to add the:
#Headers("Content-Type: application/json; charset=urf-8")
Directly after the #Multipart, to no avail. I would like to know how to correctly send my JSONObject.
User #Part instead of #Body
Since your using the Multi Part encoding, it doesn't take in just one Body object. It takes in multiple Part parameters
Related
I am making a method which can be used dynamically for all type of requests say, POST,GET and all others.
I have implemented a method like this
#HTTP(method = "{method}", path = "{url}")
fun callAPIs(
#Path(value = "method") httpMethod: String,
#Header("Authorization") auth: String,
#Header("app-version") app_version: String,
#Body data: JsonObject,
#Url url: String
): Call<JsonElement>
But I am getting error. Can anyone help me solve this error?
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.app.myapplication, PID: 17793
java.lang.IllegalArgumentException: URL "{url}" does not contain "{method}". (parameter #1)
for method APICallInterface.callAPIs
This is answered in this answer.
https://stackoverflow.com/a/37546082/4491971
Retrofit is not designed for dynamic url requests. You configure retrofit with your API base URL then make specific requests.
For a more flexible dynamic option use out OkHttp. It is the HTTP Client used by Retrofit and it easy to work with.
Backend developer gave me API description and that uses GET method and it is JSON format.
I never tried this way and as far as I know it's not possible that sending data in request body. with GET method in retrofit library.
He uses Django. And I tried with Query and Path... And nothing works... Even I tried with no annotation with the parameter.
{
"data": "oicudsfqoerzxddadsdf"
}
1.
#GET("find/data")
fun findData(
#Header("Authorization") sessionId: String,
#Query("data") data: String
): Call<FinderResult>
2.
#GET("find/data")
fun findData(
#Header("Authorization") sessionId: String,
data: String
): Call<FinderResult>
3.
#GET("find/data")
fun findData(
#Header("Authorization") sessionId: String,
dataObj: DataObj
): Call<FinderResult>
#Keep
class DataObj(var data: String){
}
All didn't work. However, It worked on Postman using raw format(should select JSON). How can I use GET request with JSON? what's the problem?
GET method purpose is only to retrieve data from server, not to send data. the only way to send data is using of query parameter in url which it's limitation is 2000 char.
When we want to use query parameter for sending data purpose we should be careful to send well-formed url characters. JSON need to be processed before attaching to URL.
So my advice is using #Query("<name of parameter which is specified by server>") and putting #FormUrlEncoded over findData method.
#FormUrlEncoded
#GET("find/data")
fun findData(
#Header("Authorization") sessionId: String,
#Query("<name of parameter which is specified by server>") data: String
): Call<FinderResult>
For more information look at:
https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/GET
https://futurestud.io/tutorials/retrofit-send-data-form-urlencoded
https://www.vogella.com/tutorials/Retrofit/article.html
I am using the retrofit library for network calls. In this, I need to pass Body in GET Method. But I am getting the error while I am passing this one. In Postman it is working while passing Body for GET Method.
#GET("http://192.168.0.141:3000/api/contacts/{page_num}/{limit}")
fun getAllContacts(#Path("page_num") page_num:Int,#Path("limit") limit:Int,#Body reqBody:ContactsInpRequest):Call<AllContactsDataResponse>
I am calling get method by passing body. But I am getting the below exception.
java.lang.IllegalArgumentException: Non-body HTTP method cannot contain #Body.
GET method does not contain body like the POST does. Here you can learn more about REST methods: https://restfulapi.net/http-methods/
EDIT: I see that you said that it works in Postman so take a look at this:
*CAN GET request have a body?
In other words, any HTTP request message is allowed to contain a message body, and thus must parse messages with that in mind. Server semantics for GET, however, are restricted such that a body, if any, has no semantic meaning to the request. ... Yes, you can send a request body with GET but it should not have any meaning.*
java.lang.IllegalArgumentException: Non-body HTTP method cannot contain #Body
This means your #GET or #DELETE should not have #Body parameter. You can use query type url or path type url or Query Map to fulfill your need. Else you can use other method annotation.
#Headers("Content-Type: application/json")
#GET("helper-url")
fun getHelperUrl(
#Query("api_token") apiToken: String,
#Query("authtype") authType: String,
#Query("channel") channel: String
): Call<ResponseHelperUrl>
Current response
Response{protocol=http/1.0, code=404, message=Not Found,
url=http://testapp*****/api/dev/myapp**/subscription%2F2be110}
But url which i'm passing is
url=http://testapp*****/api/dev/myapp**/subscription/2be110
"subscription/2be110" which is passing as string to api service which receives at following function
#Headers("Content-Type: application/json;charset=UTF-8","Accept: application/json")
#POST("{urlEndString}")
fun getResponse(
#Path ("urlEndString") urlEndString : String, #Body `object`: JsonObject
):Call<JsonObject>
How back slash changed to "%2F" format ? Any solution to resolve this issue?
Nb: using retrofit2
#Path parameters are URLEncoded. Therefore slash will be URLEncoded as well. You can use 2 path parameters like
#POST("{urlEndString1}/{urlEndString2}")
fun getResponse(
#Path ("urlEndString1") urlEndString1 : String, #Path ("urlEndString2") urlEndString2 : String, #Body `object`: JsonObject):Call<JsonObject>
And pass 2 parts of your URL ending split by slash.
As alternative, you can use #Path(value="urlEndString", encoded=true) to show that the parameter is already encoded, and Retrofit does not need to encode it.
In some post request, I don't know when to use #Field, when to use #Body.
Like whats the difference between:
#POST("users/register")
Call<String> register(#Body RequestBody registerRequest);
and:
#POST("users/register")
Call<String> register(#Field String id, #Field String pass);
Can I use #Body instead of #Field, and reverse ? If not, why ? And how to know this case use #Body, other case use #Field ?
Can you please give me some case and explain, thank you.
#Body – Sends Java objects as request body.
#Field – send data as form-urlencoded. This requires a #FormUrlEncoded annotation attached with the method.
The #Field parameter works only with a POST. #Field requires a mandatory parameter. In cases when #Field is optional, we can use #Query instead and pass a null value.
Both are used for posting data only, but they have following difference -
The #Body annotation defines a single request body.
interface Foo {
#POST("/jayson")
FooResponse postJson(#Body FooRequest body);
}
That means if you are using #Body, it should be only parameter. It is helpful when you have already a JsonObject and you want to send it as it with you api call.
Another way is, you can send data using #Field and send the Place object as a JSON string.
#POST("/post/addphoto/")
public void addImage(#Field("image_url") String url, #Field("caption") String caption, #Field("google_place_id") String placeId, #Field("facebook_place") String place, Callback<UploadCallBack> response);
Hope it will help... :-)