Retrofit: DELETE with Body in Retrofit 1.5.0

Created on 8 Apr 2014  Â·  16Comments  Â·  Source: square/retrofit

Hi,

First of all, I know that including body in DELETE request is bad, but I'm working for a customer with a legacy API, so I can't avoid it.

I'm getting this error (and the app stops):

Non-body HTTP method cannot contain @Body or @TypedOutput.

I've been having look to other responses:

https://github.com/square/retrofit/issues/330
https://github.com/square/retrofit/issues/426

But neither of them worked for me with Retrofit 1.4.1

If I use my custom DELETE annotation:

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

I get the next error (and the app doesn't stop):

Expected one of [OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, PATCH] but was DELETEWITHBODY

Is there any kind of dirty solution for now?

Thanks in advance!

Most helpful comment

With Retrofit 2 the solution is to use the HTTP interface instead of DELETE.
So replace :

@DELETE("my/path")

By

@HTTP(method = "DELETE", path = "/my/path", hasBody = true)

I would like to create my own interface DELETE_BODY but I didn't find how yet since like you said RestMethod is not available anymore.

All 16 comments

Can you paste the full stack trace? I suspect the HTTP client you are using is being overly strict.

Yep sorry, I forgot posting the full stack strace.

Trace (cause & detailMessage from Retrofit) using custom annotation:

java.net.ProtocolException: Expected one of [OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, PATCH] but was DELETEWITHBODY

Trace using DELETE:

04-09 02:40:23.237  FATAL EXCEPTION: Retrofit-Idle
    java.lang.IllegalArgumentException: UserManagementService.unsubscribeToNewsletter: Non-body HTTP method cannot contain @Body or @TypedOutput.
            at retrofit.RestMethodInfo.methodError(RestMethodInfo.java:118)
            at retrofit.RestMethodInfo.parseParameters(RestMethodInfo.java:435)
            at retrofit.RestMethodInfo.init(RestMethodInfo.java:129)
            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:1112)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
            at retrofit.Platform$Android$2$1.run(Platform.java:142)
            at java.lang.Thread.run(Thread.java:841)

For having more info, heere is my service call:

RestAdapter restAdapter = new RestAdapter.Builder().setEndpoint(Config.BASE_URL + Config.API_VERSION)
                .setClient(new CustomClient(new OkClient(), context))
                .build();

where CustomClient is:

public class CustomClient implements Client {

  private final ConnectivityManager connectivityManager;
  private Client wrappedClient;

  public CustomClient(Client wrappedClient, Context context) {
    this.wrappedClient = wrappedClient;
    connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
  }

  @Override public Response execute(Request request) throws IOException {
    final NetworkInfo activeNetwork = connectivityManager.getActiveNetworkInfo();
    final boolean isConnected = activeNetwork != null && activeNetwork.isConnectedOrConnecting();
    if (!isConnected) {
      throw new NetworkFailureException();
    }
    return wrappedClient.execute(request);
  }
}

@JakeWharton Are you planning support this in future versions?

Thank you mate!

This is a limitation by the HTTP client, not Retrofit. OkHttp version 2.0 will fix this and I'm not sure as to whether the Apache client supports this or not. We won't be able to make this work for HttpUrlConnection.

Thx!

On 22 May 2014 23:34, "Jake Wharton" [email protected] wrote:

Closed #458.

—hu
Reply to this email directly or view it on GitHub.

Hi,

I don't get it. I'm using RetroFit 1.6.0 and okhttp 2.0.0-RC2 and I'm still having the error:
Non-body HTTP method cannot contain @Body or @TypedOutput.
I'm using DELETE with a body.

Yet the issue #605: "Allow DELETE Request Body, Ensure Sane Behavior" is marked as fixed on the okhttp git repository.

Am I missing something ?

Thanks

Retrofit's @DELETE doesn't support a request body because the HTTP spec says there shouldn't be one. If you need to use a body with the DELETE method you will need to create your own HTTP annotation as mentioned above.

Which I did and it works fine.
Thanks.

Retrofit's @DELETE doesn't support a request body because the HTTP spec says there shouldn't be one.

Which HTTP spec says there shouldn't be one?

There is nothing in the specs that strictly prevent us from implementing DELETE with body. Retrofit should be flexible too.

The response is on the HTTP 1.1 RFC (http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.7)

A successful response SHOULD be 200 (OK) if the response includes an entity describing the status, 202 (Accepted) if the action has not yet been enacted, or 204 (No Content) if the action has been enacted but the response does not include an entity.

The DELETE method could return a message but isn't mandatory

@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@RestMethod(value = "DELETE", hasBody = true)
public @interface RetrofitDeleteWithBody {
    String value();
}

This worked for me, just use it like a normal DELETE except it actually works with a body!
Retrofit 1.9.

I'm using

compile 'com.google.code.gson:gson:2.5'
compile 'com.squareup.retrofit2:retrofit:2.0.2'
compile 'com.squareup.retrofit2:converter-gson:2.0.2'
compile 'com.squareup.okhttp3:okhttp:3.0.1'

But cannot find symbol RestMethod

With Retrofit 2 the solution is to use the HTTP interface instead of DELETE.
So replace :

@DELETE("my/path")

By

@HTTP(method = "DELETE", path = "/my/path", hasBody = true)

I would like to create my own interface DELETE_BODY but I didn't find how yet since like you said RestMethod is not available anymore.

Delete method is not working. In my case I use:
@DELETE("/Stories/{storyid}")
Call deleteStory(@Path("storyid") int storyId);

But its not working :( Please Help me out... !!

Was this page helpful?
0 / 5 - 0 ratings