Retrofit gives null response while calling Post request from android - android

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.

Related

Retrofit "form-urlencoded" request with #Field-annotated parameter

I have two queries:
#POST("/auth/login")
suspend fun login(#Body user: LoginUserDto): AuthResponse<TokenDto>
#FormUrlEncoded
#POST("/auth/refresh")
suspend fun refreshToken(#Field("refreshtoken") refreshToken: String): AuthResponse<TokenDto>
The first one is working well which means baseUrl is OK.
The second one returns HTTP 404 Not Found. WHen I look at Chucker interceptor logs, the url is correct and the refreshToken is present in the request. When I try to trigger it manually from request.rest in vsCode like this:
POST http://localhost:4000/auth/refresh/eyJhbGciOiJIUzI1NiIsInR5...blablabla
... it works fine.
The code of the endpoint starts like this (node.js server):
app.post('/auth/refresh/:refreshtoken', async (req, res) => {
const refreshToken = req.params.refreshtoken;
// some code
I believe I made mistake in my retrofit call refreshToken(#Field("refreshtoken") refreshToken: String).
Could smb help how make such #FormUrlEncoded request with retrofit properly?
Appreciate any help.
#Field is used to send #FormUrlEncoded request in Retrofit which hides your parameter and not attach with url to provide security.Used for POST request.
#Query parameter appended to the URL.
If you are using #Field request than it will hides your parameter and not append with the url.
If you are using #Query request than all your parameter is append to your request and visible to users.
Depend on your api request you have to use one of above annotation. If the api request accept the #FormUrlEncoded data than use #Field or if they want to attached it with url than use #Query.

how can i send json data using GET method in Retrofit?

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

How to send request body in get method retrofit

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>

Sending a JSONObject with retrofit using Kotlin

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

Using #Path and #Url paramers together with retrofit2

I'm using retrofit2 to comunicate with a webapi.
I need to set the URL of the webapi dynamically beacuase the user can change it, so i use the #Url annotation to specify it like this:
#POST
Call<LoginResponse> login(#Url String url, #Body LoginRequest user);
In one of the operations, i need to send some path parameters to the server, so i do this:
#GET
Call<DataResponse> getOrder(#Url String url,
#Header(WEBAPI_EMAIL_HEDER) String email,
#Header(WEBAPI_TOKEN_ID_HEDER) String token,
#Path("id") int id);
When i call the operation getOrder(...), an exception is rised by retrofit because i am not suppoused to use #Url and #Path parameters in the same operation.
This is the exception:
java.lang.IllegalArgumentException: #Path parameters may not be used with #Url. (parameter #4)
One solution is to replace the id parameter on the url and use only the #Url parameter in the invokation. But i think this is not the best way, beacuase i will be doing this with all the operations with #Path parameters.
Is there any other cleaner solution? Maybe using another retrofit2 annotation?
Thanks in advance.
As described in the post Retrofit 2 - Dynamic URL, the #Url notation assumes that the String is a fully defined URL and does not check whether it contains #Path variables.
To use the #Path annotation, you have to configure an endpoint URL and include the #Path variable inside the #GET() annotation.
There is a workaround. Incase of a dynamic Url with some variable path, we can define a string format with paths denoted by %s arguments.
E.g:
Suppose the dynamic url with path is : https://www.example.com/users/{id}/whoami
Here we can just replace {id} with %s. So now it becomes,
val formatString = https://www.example.com/users/%s/whoami
Now we can use it as a format string and replace it with required id.
val url = formatString.format(id)
and in the retrofit interface, use #Url parameter in the function.
interface AnyService {
fun whoAmI(#Url url:String): Call<ResponseBody>
}
Incase you are using MVVM architecture, you can call the formatting code in the concerned repository.

Categories

Resources