Apache HttpComponents 5: POST form data with HttpAsyncClient

I am looking for a solution to POST form data with HttpAsyncClient. All examples I’ve found so far only sent simple GET requests. This is what I’ve got so far:

try (CloseableHttpAsyncClient client = HttpAsyncClients.createDefault()) {
  SimpleHttpRequest httpPost = SimpleHttpRequests.post("http://httpbin.org");
  // How to add key=value as form data to httpPost?
  Future<SimpleHttpResponse> future = client.execute(httpPost, new FutureCallback<SimpleHttpResponse>() {
    @Override
    public void completed(SimpleHttpResponse simpleHttpResponse) {
      System.out.println(simpleHttpResponse.getCode());
      System.out.println(simpleHttpResponse.getBody());
    }

    @Override
    public void failed(Exception e) {
      System.out.println(e);
    }

    @Override
    public void cancelled() {
      System.out.println("cancelled");
    }
  }
}

I also looked around the source code, where I found the SimpleHttpRequest::setBody method and the corresponding SimpleBody class. But they seem, too, not support form data.

Basically, I need the equivalent of OkHttp‘s FormBody.

Answer

After some digging through the documentation and source code of Apache HttpComponents 5, I came up with the following solution. Instead of using SimpleHttpRequests, I need to create an AsyncRequestProducer and an AsyncResponseConsumer. The request producer object defines how to create my request and in contrast to the SimpleHttpRequest, it is able to also produce the form body that I need. Example code:

try (CloseableHttpAsyncClient client = HttpAsyncClients.createDefault()) {
  client.start();
  AsyncRequestProducer producer = AsyncRequestBuilder.post()
          .setUri("http://httpbin.org")
          .addParameter("key", "value") // <- form parameters in body
          .build();
  AsyncResponseConsumer<SimpleHttpResponse> consumer = SimpleResponseConsumer.create();
  client.execute(producer, consumer, new FutureCallback<SimpleHttpResponse>() {
    @Override
    public void completed(SimpleHttpResponse simpleHttpResponse) {
      System.out.println(simpleHttpResponse.getCode());
      System.out.println(simpleHttpResponse.getBody());
    }

    @Override
    public void failed(Exception e) {
      System.out.println(e);
    }

    @Override
    public void cancelled() {
      System.out.println("cancelled");
    }
  });
}

Alternatively, I could use an AsyncEntityProducer to produce the form body:

Iterable<NameValuePair> params = Stream.of(new BasicNameValuePair("key", "value"))
        .collect(Collectors.toList());
AsyncEntityProducer entityProducer = AsyncEntityProducers.createUrlEncoded(params, Charsets.UTF_8);
AsyncRequestProducer producer = AsyncRequestBuilder.post()
        .setUri("http://httpbin.org")
        .setEntity(entityProducer)
        .build();