Retrofit throwing IllegalArgumentException exception for asynchronous FormUrlEncoded DELETE call

StackOverflow https://stackoverflow.com/questions/22572301

Вопрос

I'm trying to make an asynchronous POST and DELETE which is form url encoded using Retrofit in Android 4.4

Here is my client -

@FormUrlEncoded
@POST(INetwork.API_BASE_PREFIX + "/memberships.json")
void join(@Field("id") String id, Callback<?> cb);

@FormUrlEncoded
@DELETE(INetwork.API_BASE_PREFIX + "/memberships.json")
void leave(@Field("id") String id, Callback<?> cb);

And this is the exception -

java.lang.IllegalArgumentException: IRepositoryClient.leave: FormUrlEncoded can only be specified on HTTP methods with request body (e.g., @POST).
        at retrofit.RestMethodInfo.methodError(RestMethodInfo.java:118)
        at retrofit.RestMethodInfo.parseMethodAnnotations(RestMethodInfo.java:191)
        at retrofit.RestMethodInfo.init(RestMethodInfo.java:128)
        at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:329)
        at retrofit.RestAdapter$RestHandler.access$100(RestAdapter.java:264)
        at retrofit.RestAdapter$RestHandler$2.obtainResponse(RestAdapter.java:315)
        at retrofit.CallbackRunnable.run(CallbackRunnable.java:42)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
        at retrofit.Platform$Android$2$1.run(Platform.java:142)
        at java.lang.Thread.run(Thread.java:841)

I looked through the source and it basically if the method doesn't have a body and the request is formurlencoded, this exception is thrown. Also I noticed that all example of FormUrlEncoded work fine when it is not asynchronous, i.e. I have a return type of some sort and no callback - sorry I'm a little lost

Should I send an empty body? Am I required to send one and won't the @Field parameters suffice?

Using Retrofit 1.5.0

Это было полезно?

Решение

The RFC for HTTP is unclear on whether or not the DELETE method is allowed to have a request body or not. Retrofit is raising an error on the side of caution by not having one.

However, you can still include one (assuming the HTTP client supports it) by using a custom HTTP method annotation.

package com.myapp;

@Target(METHOD)
@Retention(RUNTIME)
@RestMethod(value = "DELETE", hasBody = true)
public @interface BODY_DELETE {
  String value();
}

Now specify your interface method using the custom annotation that you defined.

@FormUrlEncoded
@BODY_DELETE(INetwork.API_BASE_PREFIX + "/memberships.json")
void leave(@Field("id") String id, Callback<?> cb);

Другие советы

Updated answer for Retrofit 2.0:

Retrofit 2 doesn't seem to have @RestMethod any more, so here is what works:

@FormUrlEncoded
@HTTP(method = "DELETE", path = INetwork.API_BASE_PREFIX + "/memberships.json", hasBody = true)
void leave(@Field("id") String id, Callback<?> cb);

For retrofit 2.+

@FormUrlEncoded
@HTTP(method = "DELETE", path = INetwork.API_BASE_PREFIX + "/memberships.json", hasBody = true)
Callback<?> cb(@Field("id") String id);

and for RxRetrofit 2.+

@FormUrlEncoded
@HTTP(method = "DELETE", path = INetwork.API_BASE_PREFIX + "/memberships.json", hasBody = true)
Observable<?> cb(@Field("id") String id);
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top