HTTP Client 4 and a JSON endpoint

August 17, 2017

I need to POST to a HTTPS JSON based service endpoint in Java. I can do this using Http Client 4.

In the following code, SERVICE_ENDPOINT is the full URL to the service, in my case https://" + SERVICE_HOST + "/v2/. The other values should be self explanatory, and are all strings apart from port numbers which are integers.

First we setup the SSL details, including restricting the algorithm to the newer TLS 1.2.

PlainConnectionSocketFactory lPlainSocketFactory = PlainConnectionSocketFactory.getSocketFactory();
String lAlgorithm = "TLSv1.2";
SSLContext lSslContext = SSLContexts.custom().useProtocol(lAlgorithm).build();
SSLConnectionSocketFactory lSSLFactory = new SSLConnectionSocketFactory(lSslContext);
Registry<ConnectionSocketFactory> lRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
                  .register("http", lPlainSocketFactory)
                  .register("https", lSSLFactory).build();

Next we create the connection manager and client builder.

// Create connection manager
BasicHttpClientConnectionManager lConnectionManager = new BasicHttpClientConnectionManager(lRegistry);
HttpClientBuilder lClientBuilder = HttpClients.custom().setConnectionManager(lConnectionManager);

We now need to set up our proxy server.

HttpHost proxy = new HttpHost(this.proxyHost, this.proxyPort);
DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy);
lClientBuilder.setRoutePlanner(routePlanner);

We are using HTTP Basic Auth for both the proxy and the endpoint service, so we need to set up both of those.

HttpHost lTargetHost = new HttpHost(SERVICE_HOST, SERVICE_PORT, "https");
CredentialsProvider lCredentialsProvider = new BasicCredentialsProvider();
lCredentialsProvider.setCredentials(new AuthScope(this.proxyHost, this.proxyPort), 
                                                   new UsernamePasswordCredentials(this.proxyUsername, this.proxyPassword));
lCredentialsProvider.setCredentials(new AuthScope(SERVICE_HOST, SERVICE_PORT), 
                                                   new UsernamePasswordCredentials(this.apiKey, this.apiPassword));
lClientBuilder.setDefaultCredentialsProvider(lCredentialsProvider);

We can now specify a timeout for the connection - SERVICE_TIMEOUT is a number of seconds as an int.

RequestConfig config = RequestConfig.custom().setSocketTimeout(SERVICE_TIMEOUT * 1000).setConnectTimeout(SERVICE_TIMEOUT * 1000).build();
lClientBuilder.setDefaultRequestConfig(config);

Finally we can create the client, and then convert the calling JSON from a string into a StringEntity.

CloseableHttpClient lHttpClient = lClientBuilder.build();
StringEntity lJsonBody = new StringEntity(pJsonPayload);

Next we call the service, using a POST.

HttpClientContext lContext = HttpClientContext.create();
CloseableHttpResponse lHttpResponse = null;
HttpPost lMethod = new HttpPost(SERVICE_ENDPOINT);
lMethod.addHeader("Content-Type", "application/json");
lMethod.setEntity(lJsonBody);
lHttpResponse = lHttpClient.execute(lMethod, lContext);

Once complete, we can deal with the response

if ((lHttpResponse.getStatusLine() != null) && (lHttpResponse.getStatusLine().getStatusCode() == 401))
{
  throw new RuntimeException("Error, getting 401 unauthorised.");
}
else if ((lHttpResponse.getStatusLine() != null) 
                   && lHttpResponse.getStatusLine().getStatusCode() != 500
                   && (((lHttpResponse.getStatusLine().getStatusCode() >= 200) 
                   && (lHttpResponse.getStatusLine().getStatusCode() <= 299)) == false))
{
  String lError = "";
  try
  {
    lError = EntityUtils.toString(lHttpResponse.getEntity());
  }
  catch (ParseException | IOException lException)
  {
    throw new RuntimeException(lException);
  }
  throw new RuntimeException("Error, [" + lHttpResponse.getStatusLine() + "] " + lError);
}

String lResponse = null;

try
{
  lResponse = EntityUtils.toString(lHttpResponse.getEntity());
}
catch (ParseException | IOException lException)
{
  throw new RuntimeException("Can't parse response" + lException);
}

return lResponse;