75

I m trying to make a request in which I want to include a Header , a form-urlencoded field and a json body. My Retrofit interface is as follows

@FormUrlEncoded
@POST("/api/register")
Observable<RegisterResponse> register(
    @Header("Authorization") String authorization, 
    @Field("grant_type") String grantType, 
    @Body RegisterBody body
);

When I make this request I get back exception @Body parameters cannot be used with form or multi-part encoding.
I have also tried with the @Multipart annotation:

@Multipart
@FormUrlEncoded
@POST("/api/register")
Observable<RegisterResponse> register(
    @Header("Authorization") String authorization, 
    @Part("grant_type") TypedString grantType, 
    @Body RegisterBody body
);

and I get an IllegalArgumentException and only one encoding annotation is allowed.

Chris
  • 1,641
  • 1
  • 16
  • 17
  • possible duplicate of [Multipart Request using Retrofit 1.8.0 not working](http://stackoverflow.com/questions/21582453/multipart-request-using-retrofit-1-8-0-not-working) – njzk2 Dec 05 '14 at 16:21
  • 1
    also, since it is a multipart, you need several @Part, not a Body and a Part – njzk2 Dec 05 '14 at 16:22

5 Answers5

114

maybe this could help some people, if you have this trouble, you should remove @FormUrlEncoded of your interface.

starball
  • 20,030
  • 7
  • 43
  • 238
Julien Athomas
  • 1,157
  • 2
  • 8
  • 5
25

This post pointed me to the right direction https://stackoverflow.com/a/21423093/1446856. I attached everything in the body and send it as a TypedInput.
So the interface looks something like this

@POST("/api/register")
@Headers({ "Content-Type: application/json;charset=UTF-8"})
Observable<RegisterResponse> register(
    @Header("Authorization") String authorization,
    @Body TypedInput body
);

and the body looks something like this

String bodyString = jsonBody + "?grant_type=" + 
    grantType + "&scope=" + scope;
TypedInput requestBody = new TypedByteArray(
    "application/json", bodyString.getBytes(Charset.forName("UTF-8")));
Community
  • 1
  • 1
Chris
  • 1,641
  • 1
  • 16
  • 17
9

Adding to Julien's answer, also remove the @Multipart annotation. Here's how I have used it:

@POST("/app/oauth/token")
Call<AuthResponse> getAuthToken(@Body RequestBody body);

And, here is how I have constructed the RequestBody:

RequestBody requestBody = new MultipartBody.Builder()
                        .setType(MultipartBody.FORM)
                        .addFormDataPart("grant_type", "password")
                        .addFormDataPart("username", username)
                        .addFormDataPart("password", password)
                        .build();
Prince
  • 20,353
  • 6
  • 39
  • 59
1

I solved this problem by adding the field into

@POST("/api/register") 

like this:

@POST("/api/register?grantType=value")

it's not a good solution, but may be useful.

Pedro del Sol
  • 2,840
  • 9
  • 39
  • 52
Matt.Young
  • 11
  • 2
0

Send Authentication header with json Body to API sample code in Kotlin :

 @POST("/api/user/sendlist/")
    fun callSendJsonListPost(
                      @Header("Authheader") header: String,
                      @Body list: StringBuilder
                      )
        : Observable<EntityModelUserslist>
Hamed Jaliliani
  • 2,789
  • 24
  • 31