40

When I try to create a delete method:

public interface ImageService {
    @DELETE("api/v1/attachment")
    Call<BaseResponse> delete(@Body DeleteModel deleteModel);
}

I get the error which basically boils down to these lines from the stacktrace:

E/AndroidRuntime: FATAL EXCEPTION: main
java.lang.RuntimeException: Failure delivering result
java.lang.IllegalArgumentException: Non-body HTTP method cannot contain @Body.
Caused by: java.lang.IllegalArgumentException: Non-body HTTP method cannot contain @Body.

How can I add a body to a delete method ?

I have searched here but found 3 not answers and nothing using retrofit.

HopefullyHelpful
  • 1,652
  • 3
  • 21
  • 37

8 Answers8

96

A more simplified answer.

@HTTP(method = "DELETE", path = "/api/analysis_delete", hasBody = true)
Call<Analysis_Delete_RequestResult_Api10> analysis_delete_api10(@Field("seq") String seq);

This will do the trick.

murgupluoglu
  • 6,524
  • 4
  • 33
  • 43
March3April4
  • 2,131
  • 1
  • 18
  • 37
19

Here is my version

@HTTP(method = "DELETE", path = "{login}", hasBody = true)
Call<ResponseBody> getData(@Path("login") String postfix, @Body Map<String, Object> options);
Jens Borrisholt
  • 6,174
  • 1
  • 33
  • 67
Sharanjeet Kaur
  • 796
  • 13
  • 18
14

Here's an excerpt from the docs, it's a documented feature of the HTTP annotation.

This annotation can also used for sending DELETE with a request body:

 interface Service {
   @HTTP(method = "DELETE", path = "remove/", hasBody = true)
   Call<ResponseBody> deleteObject(@Body RequestBody object);
 }

https://square.github.io/retrofit/2.x/retrofit/retrofit2/http/HTTP.html

headsvk
  • 2,726
  • 1
  • 19
  • 23
7

In case you are you are using an old version that doesn't support @HTTP, you can also add another interface that implements the @RestMethod

import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import retrofit.http.RestMethod;

import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

/** Make a DELETE request to a REST path relative to base URL with body. */
@Target(METHOD)
@Retention(RUNTIME)
@RestMethod(value = "DELETE", hasBody = true)
public @interface DELETEWITHBODY {
  String value();
}

And then the usage becomes:

public interface ImageService {
    @DELETEWITHBODY("api/v1/attachment")
    Call<BaseResponse> delete(@Body DeleteModel deleteModel);
}
Yftach
  • 712
  • 5
  • 15
2

This works for me (Kotlin)

for deleting multiple objects (as key-value pair)

@HTTP(method = "DELETE", path = "api/v1/attachment", hasBody = true)
fun getData(@Body requestBody: Map<String, DeleteModel>): Callable<ResponseBody>

Or for deleting one object

@HTTP(method = "DELETE", path = "api/v1/attachment", hasBody = true)
fun getData(@Body requestBody: DeleteModel): Callable<ResponseBody>
MohamedHarmoush
  • 1,033
  • 11
  • 17
0

the service:

public interface ImageService {
    @Post("api/v1/attachment")
    Call<BaseResponse> delete(@Body DeleteModel deleteModel);
}

and in the servercontroller

import okhttp3.Request;

private final class ApiInterceptor implements Interceptor {

    @Override
    public Response intercept(Chain chain) throws IOException {
        Request oldRequest = chain.request();
        Request.Builder builder = oldRequest.newBuilder();
        if(condition) {
            return chain.proceed(builder.build().newBuilder().delete(builder.build().body()).build());
        }
        return chain.proceed(builder.build());
    }
}

you have to trigger condition, via something and potentially have to do some filtering for the url/header/body to remove the trigger,

unless the delete url/body/header is unique enough to not collide with post or get requests.

HopefullyHelpful
  • 1,652
  • 3
  • 21
  • 37
0

Originally answered here : https://stackoverflow.com/a/62920127/8956093

Kotlin Code :

path is not required if your first argument to interface method is a url annotated with @Url Example :

@HTTP(method = "DELETE", hasBody = true)
fun deleteStudentFromDatabase(
    @Url url: String,
    @Body payload: StudentModel
 ): Observable<Any>

If first argument to interface method is not a url then use this

    @HTTP(method = "DELETE", path = "{urlPath}", hasBody = true)
    fun deleteStudentFromDatabase(
        @Body payload: StudentModel,
        @Path("urlPath") url: String
     ): Observable<Any>
Ramakrishna Joshi
  • 1,442
  • 17
  • 22
0

I faced the same issue, I hope it will help others

I use: Kotlin, Retrofit, Coroutines

@FormUrlEncoded
@HTTP(method = "DELETE", path = "your_end_point_path", hasBody = true)
suspend fun delete(
    @Field("id") id: String
): Response<BaseResponse<*>>
Eng.OsamaYousef
  • 458
  • 2
  • 5
  • 10