How to use custom HTTP clients with Twilio in Java

October 12, 2020
Written by
Reviewed by
Liz Moy
Twilion

Title: How to use custom HTTP clients with Twilio in Java

[Header image adapted from this image, CC BY 2.0 from Microsoft NYC]

When building a Java application that uses Twilio's API most developers will have code that runs at startup, initializing the Twilio helper library like this:

Twilio.init(
    TWILIO_ACCOUNT_SID,
    TWILIO_AUTH_TOKEN);

This sets the account credentials as static fields in the Twilio class. Effectively they are now global settings for the application, and when your code calls the API these will be used automatically, and the helper library creates an HTTP client for you. This means that you don't have to repeat your credentials every time you call a method that uses the Twilio API:

Message.creator(TO_NUMBER, FROM_NUMBER, "Hello 👋").create();

This is convenient, however there are cases where you want more control over the HTTP client. This might be to configure an HTTP proxy, or to provide custom credentials if you are using multiple Twilio accounts or Projects in the same codebase.

To enable this, all the methods which call the Twilio API are overloaded to take an instance of TwilioRestClient. If you pass a TwilioRestClient each time you call any of the create/read/update/delete methods, you will no longer need to call Twilio.init(), you can customize your HTTP clients and use as many different instances of them as you need.

In this post I'll show how to do that for a couple of common cases:

  • Using multiple sets of Twilio credentials
  • Calling the Twilio API through an HTTP proxy

The code samples are all in a repo on GitHub, too.

Using custom HTTP clients to work with multiple sets of credentials

If you're using several Twilio accounts or Projects in one application, you shouldn’t configure your Account SID and Auth Token globally. Instead, you can use the builder pattern provided by TwilioRestClient to create as many clients as you need. Here's an example where I've been working on two apps ("Cake" and "Pie") using different Twilio Projects with different credentials and phone numbers:

TwilioRestClient cakeClient = new TwilioRestClient.Builder(
    Secrets.PROJECT_CAKE_ACCOUNT_SID,
    Secrets.PROJECT_CAKE_AUTH_TOKEN)
  .build();

TwilioRestClient pieClient = new TwilioRestClient.Builder(
    Secrets.PROJECT_PIE_ACCOUNT_SID,
    Secrets.PROJECT_PIE_AUTH_TOKEN)
  .build();

Message.creator(
    TO_PHONE_NUMBER,
    PROJECT_CAKE_PHONE_NUMBER,
    "Cake is best! 🎂")
  .create(cakeClient);

Message.creator(
    TO_PHONE_NUMBER,
    PROJECT_PIE_PHONE_NUMBER,
    "No, Pie is better! 🥧")
  .create(pieClient);

[Full source on GitHub]

By passing in a TwilioRestClient client to each call to .create I can control which Project is used (and billed) for each message. To make sure I keep my two sets of credentials safe, the Secrets class loads them from environment variables.

Using a custom HTTP client with an HTTP proxy

Twilio's API lives on the internet, and many folks on corporate networks will therefore need to configure an HTTP proxy to access it. Again this is possible with a custom TwilioRestClient, although in this case we'll need to write some code of our own. There are a few layers to this, so let's unpack them:

  • A TwilioRestClient builder can take a custom instance of com.twilio.http.HttpClient. (This would be a good place to inject a mock for testing your calls to the Twilio API)
  • The default implementation of Twilio's HttpClient is called NetworkHttpClient.
  • NetworkHttpClient can be initialised with an Apache HttpComponents HttpClientBuilder.
  • HttpClientBuilder can be configured to use a proxy.

To create an HttpClient instance, this code is sufficient:

private static HttpClient createProxiedHttpClient(String proxyHost, int proxyPort) {

   // you can also configure things like caching, custom HTTPS certs,
   // timeouts and connection pool sizes here.
   // See: https://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/impl/client/HttpClientBuilder.html
   HttpClientBuilder apacheClientBuilder = HttpClientBuilder.create()
       .setProxy(new HttpHost(proxyHost, proxyPort));

   return new NetworkHttpClient(apacheClientBuilder);
}

Then, use that method to create a proxied client and add it to your code like this:

// These are the defaults for tinyproxy: http://tinyproxy.github.io/
// Configure these for your environment
private static final String PROXY_HOST = "localhost";
private static final int PROXY_PORT = 8888;

public static void main(String[] args) {

   HttpClient proxiedHttpClient = createProxiedHttpClient(PROXY_HOST, PROXY_PORT);

   TwilioRestClient proxiedTwilioClient = new TwilioRestClient.Builder(
       PROJECT_CAKE_ACCOUNT_SID,
       PROJECT_CAKE_AUTH_TOKEN)
       .httpClient(proxiedHttpClient)
       .build();

   Message.creator(
       TO_PHONE_NUMBER,
       PROJECT_CAKE_PHONE_NUMBER,
       "Cake, or Pie?")
       .create(proxiedTwilioClient);
}

[Full source on GitHub]

In Summary

Using the defaults for configuring your Twilio credentials and creating an HTTP client is convenient, but there are definitely times when a bit more control is needed. I've shown a couple of typical cases, and if you need more control the Apache HttpClientBuilder docs are comprehensive.

If you're building with Twilio, I'd love to hear about it. Let me know what you're up to - I can't wait to see what you build:

🐦 @MaximumGilliard

📧 mgilliard@twilio.com