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

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.

Related

Retrofit POST Request and FormUrlEncoded with :Id in url

I am trying to integrate stripe API and I ran into the problem while using #POST and #FormUrlEncoding annotation.
The stripe has the following Url. https://api.stripe.com/v1/customers/:id/sources
The API need FormUrlEncoded and POST request. I have no idea how to pass that id in the URL.
#POST("https://api.stripe.com/v1/customers/:id/sources")
#FormUrlEncoded
Completable createBankAccount(#Field("source") String bankToken);
You should pass id as a path parameter.
So your endpoint will be as following:
#POST("https://api.stripe.com/v1/customers/{id}/sources")
#FormUrlEncoded
Completable createBankAccount(#Path("id") int id,#Field("source") String bankToken);

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>

What is the difference between #Field and #Query in retrofit

In some POST requests, I don't know when to use #Field with FormUrlEncoded and when to use #Query
For Example:
#POST("list-products-for-sale")
Call<ListAllProductsResponse> getNewProducts(#HeaderMap Map<String,
String> headers,#Query("lastProductId") String lastProductId);
When I tried to use #Field here it was not responding properly and when I switched it to #Query it's working great.
I want to know why #Field isn't working while Query can work perfectly and I did tested in POSTMAN where I sent the data as a formurlencoded and it's giving me the results fin.
EDIT
BTW I'm passing Content-Type:application/json, Accept: application/json with an Authorization key
#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.
You can get more information from below link :
1) https://square.github.io/retrofit/2.x/retrofit/index.html?retrofit2/http/Query.html
2) https://square.github.io/retrofit/2.x/retrofit/retrofit2/http/Field.html

Adding dynamic header to POST request with body (Retrofit v2.4.0)

I am using Retrofit v2.4.0 in my project. I need to get token using one API call and using this token in header of the POST request I should use another API call where I should add one header and two parameter to the body of the request. The following code is of the second API call (JavaRx is used):
#FormUrlEncoded
#POST("auth/sendCode")
#Headers("Content-Type: application/json")
Single<SendCodeResponse> sendCode(#Header("token") String token,
#Field("phoneNumber") String phoneNumber,
#Field("langCode") String langCode);
However, it is not working. When I log my request, it is showing that the request body is not correct.
What is wrong with my code above?

Retrofit GET without a value in Android

I use Retrofit for most of my calls but in one of the cases, I have the full path provided in arguments. My URL is like this http://www.example.com/android.json. This URL is provided in full so I have to path it at runtime. I implement endpoint as suggested here
https://medium.com/#kevintcoughlin/dynamic-endpoints-with-retrofit-a1f4229f4a8d
but in the #GET I need to be able to put #GET(""). This does not work as I get an error saying I should provide at least one "/".
If I add the slash the URL becomes http://www.example.com/android.json/ and it does not work, the server returns forbidden. I also tried creating a custom GET interface similar to here https://github.com/square/retrofit/issues/458 but with GET and without providing a value method in the interface. Then I get another error saying value is missing.
Basically I need to be able to provide an empty or null value but retrofit does not allow that. How could I solve this problem? For now I am doing the JSON request manually but is there a way I could use retrofit for this case? I need to pass the full URL there is no way I can do endpoint http://www.example.com and #GET("/android.json").
Thanks
You can use #GET(".") to indicate that your url is the same as the base url.
#GET(".")
Observable<Result> getData(#Query("param") String parameter);
I've tried this approach, however didn't work for me.
Workaround for this issue is:
//Retrofit interface
public interface TestResourceClient {
#GET
Observable<Something> getSomething(#Url String anEmptyString);
}
//client call
Retrofit.Builder().baseUrl("absolute URL").build()
.create(TestResourceClient.class).getSomething("");
The downside of this solution is that you have to supply empty string in getSomething("") method call.
I face the same problem with Retrofit 2. Using #GET, #GET("") and #GET(".") not solved my problem.
According to the official document you can the same baseUrl and #GET argument.
Endpoint values may be a full URL.
Values that have a host replace the host of baseUrl and values also with a scheme replace the scheme of baseUrl.
Base URL: http://example.com/
Endpoint: https://github.com/square/retrofit/
Result: https://github.com/square/retrofit/
So in my case:
interface MyAPI {
#GET("http://www.omdbapi.com/")
suspend fun getMovies(
#Query("apikey") apikey: String,
#Query("s") s: String
): Response<MoviesResponse>
companion object {
operator fun invoke(): MyAPI {
return Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl("http://www.omdbapi.com/")
.build()
.create(MyAPI::class.java)
}
}
}

Categories

Resources