Java HTTP DELETE with Request Body
Asked Answered
C

5

9

I have an external API which uses DELETE with the body(JSON). I make use of Postman REST Client and get the delete done with request body and it works fine. I am trying to automate this functionality using a method.

I tried HttpURLConnection for similar GET, POST and PUT. But I am not sure how to use the DELETE with a request body.

I have checked in StackOverflow and see this cannot be done, but they are very old answers.

Can someone please help? I'm using spring framework.

Caprice answered 5/4, 2017 at 20:53 Comment(5)
Does this help you? #300128. It seems that with DELETE, the request body should be ignored.Ashburn
I have read that article, however, the external API which I use has to have the bodyCaprice
Which third-party API is this? Is it a third-party API used by a third-party product, or a third-party API used by a product you are developing? In the former case, you're pretty much stuck with it, but in the latter case, your organization could choose to use a library with a more common (better supported) syntax.Aborigine
It's an in-house application service of my org, accessible only through the same network. I'm trying to hit that production API with my API.Caprice
Typically only POST, PUT and PATCH use request bodies, so at least that is not a REST API - seems to be a bad design at all.Slit
C
15

I used org.apache.http to get this done.

@NotThreadSafe
class HttpDeleteWithBody extends HttpEntityEnclosingRequestBase {
    public static final String METHOD_NAME = "DELETE";

    public String getMethod() {
        return METHOD_NAME;
    }

    public HttpDeleteWithBody(final String uri) {
        super();
        setURI(URI.create(uri));
    }

    public HttpDeleteWithBody(final URI uri) {
        super();
        setURI(uri);
    }

    public HttpDeleteWithBody() {
        super();
    }
}



public String[] sendDelete(String URL, String PARAMS, String header) throws IOException {
    String[] restResponse = new String[2];
        CloseableHttpClient httpclient = HttpClients.createDefault();

        HttpDeleteWithBody httpDelete = new HttpDeleteWithBody(URL);
        StringEntity input = new StringEntity(PARAMS, ContentType.APPLICATION_JSON);
        httpDelete.addHeader("header", header);
        httpDelete.setEntity(input);  

        Header requestHeaders[] = httpDelete.getAllHeaders();
        CloseableHttpResponse response = httpclient.execute(httpDelete);
        restResponse[0] = Integer.toString((response.getStatusLine().getStatusCode()));
        restResponse[1] = EntityUtils.toString(response.getEntity());    
        return restResponse;
    }
}
Caprice answered 6/4, 2017 at 21:13 Comment(1)
Got the answer from daweini.wordpress.com/2013/12/20/…Caprice
D
5

If you are using Spring, you can use RestTemplate to generate the client request. In this case you could use RestTemplate.exchange and provide the url, http method and request body. Something like (not tested, but you get the idea):

RestTemplate restTemplate = new RestTemplate();
HttpEntity<Foo> request = new HttpEntity<>(new Foo("bar"));
restTemplate.exchange(url, HttpMethod.DELETE, request, null);
Darter answered 5/4, 2017 at 23:47 Comment(1)
This will drop the body and always return 400Swale
C
2

This code worked for me:-

  • You set content type by httpCon.setRequestProperty
  • You set the request Method by httpCon.setRequestMethod
  • Write the json body into OutputStreamWriter, in my sample, i converted Java object to json using Jackson ObjectMapper

    URL url = new URL("http://localhost:8080/greeting");
    HttpURLConnection httpCon = (HttpURLConnection) url.openConnection();
    httpCon.setDoOutput(true);
    httpCon.setRequestProperty(
                    "Content-Type", "application/json");
    httpCon.setRequestMethod("DELETE");
    OutputStreamWriter out = new OutputStreamWriter(
                    httpCon.getOutputStream());
    ObjectMapper objectMapper = new ObjectMapper();
    out.write(objectMapper.writeValueAsString(new Greeting("foo")));
    out.close();
    httpCon.connect();
    
Counterclaim answered 6/4, 2017 at 10:34 Comment(0)
G
1

There is a method called method in java.net.http.HttpRequest that accepts arbitrary HTTP method name and BodyPublisher:

/**
 * Sets the request method and request body of this builder to the
 * given values.
 *
 * @apiNote The {@link BodyPublishers#noBody() noBody} request
 * body publisher can be used where no request body is required or
 * appropriate. Whether a method is restricted, or not, is
 * implementation specific. For example, some implementations may choose
 * to restrict the {@code CONNECT} method.
 *
 * @param method the method to use
 * @param bodyPublisher the body publisher
 * @return this builder
 * @throws IllegalArgumentException if the method name is not
 *         valid, see <a href="https://tools.ietf.org/html/rfc7230#section-3.1.1">
 *         RFC 7230 section-3.1.1</a>, or the method is restricted by the
 *         implementation.
 */
public Builder method(String method, BodyPublisher bodyPublisher);

So to create DELETE request with body all you need to do is:

HttpRequest.newBuilder(URI.create("https://api..."))
    .method("DELETE", HttpRequest.BodyPublishers.ofString("{\"filed_name\":\"filed_value\"}"))
    .build();
Googins answered 13/7 at 9:40 Comment(1)
IMHO the best way when you don't want to use any 3rd party library. thanks!Papism
P
-1

Isn't easy just to override the getMethod() method of the HttpPost class?

private String curl(                    // Return JSON String
        String method,                  // HTTP method, for this example the method parameter should be "DELETE", but it could be PUT, POST, or GET.
        String url,                     // Target URL  
        String path,                    // API Path
        Map<String, Object> queryParams,// Query map forms URI
        Map<String, Object> postParams) // Post Map serialized to JSON and is put in the header
        throws Error,               // when API returns an error
        ConnectionClosedException       // when we cannot contact the API
{
   HttpClient client = HttpClients.custom()
            .setDefaultRequestConfig(
                    RequestConfig.custom()
                            .setCookieSpec(CookieSpecs.STANDARD)
                            .build()
            ).build();


    HttpPost req = new HttpPost(){
        @Override
        public String getMethod() {
            // lets override the getMethod since it is the only
            // thing that differs between each of the subclasses
            // of HttpEntityEnclosingRequestBase. Let's just return
            // our method parameter in the curl method signature.
            return method;
        }
    };

    // set headers
    req.setHeader("user-agent", "Apache");
    req.setHeader("Content-type", "application/json");
    req.setHeader("Accept", "application/json");

    try {
        // prepare base url
        URIBuilder uriBuilder = new URIBuilder(url + path);

        if (method.equals("GET")){
            queryParams.forEach((k, v)-> uriBuilder.addParameter(k, v.toString()));
        }else{
            String postPramsJson = new Gson().toJson(postParams);
            req.setEntity(new StringEntity(postPramsJson));
        }

        // set the uri
        req.setURI(uriBuilder.build().normalize());

        // execute the query
        final HttpResponse response = client.execute(req);

        //
        if (response.getEntity() != null) {
            if(response.getStatusLine().getStatusCode() == 200){
                 return EntityUtils.toString(response.getEntity());
            }
            logger.error("ERROR: Response code " + response.getStatusLine().getStatusCode() +
                     ", respnse: " + EntityUtils.toString(responseEntry));
        }
        throw new Error("HTTP Error");
    } catch (Exception e) {
        logger.error("Connection error", e);
        throw new ConnectionClosedException("Cannot connect to " + url);
    }
}

The point is rather than having to add another class to your package... Why not just override getMethod() in an already sub-classed object of HttpEntityEnclosingRequestBase?

Pianissimo answered 17/6, 2018 at 17:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.