Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 406
AkshayT Avatar asked Jun 14 '16 14:06

AkshayT


People also ask

What is form urlencoded Retrofit?

Annotation Type FormUrlEncodedDenotes that the request body will use form URL encoding. Fields should be declared as parameters and annotated with @Field . Requests made with this annotation will have application/x-www-form-urlencoded MIME type.


4 Answers

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.

like image 138
Monster Brain Avatar answered Oct 09 '22 23:10

Monster Brain


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);
like image 42
ikhsanudinhakim Avatar answered Oct 10 '22 00:10

ikhsanudinhakim


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", "[email protected]")
      .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>
like image 4
Sumit Pansuriya Avatar answered Oct 10 '22 01:10

Sumit Pansuriya


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.

like image 7
CoolMind Avatar answered Oct 10 '22 00:10

CoolMind