Calling a Thrift service

Let's assume we have the following Thrift IDL, served at http://127.0.0.1:8080/hello, just like what we used in Running a Thrift service:

namespace java com.example.thrift.hello

service HelloService {
    string hello(1:string name)
}

Making a call starts from creating a client:

import com.linecorp.armeria.client.thrift.ThriftClients;

// Use the tbinary format by default.
HelloService.Iface helloService = ThriftClients.newClient(
    "http://127.0.0.1:8080/hello",
    HelloService.Iface.class); // or AsyncIface.class

String greeting = helloService.hello("Armerian World");
assert greeting.equals("Hello, Armerian World!");

Note that if a serialization format is unspecified, ThriftSerializationFormats.BINARY is used by default. You can also specify one of ThriftSerializationFormats.BINARY, ThriftSerializationFormats.COMPACT, ThriftSerializationFormats.JSON and ThriftSerializationFormats.TEXT using ThriftClientBuilder.serializationFormat().

import com.linecorp.armeria.common.thrift.ThriftSerializationFormats;

HelloService.Iface helloService =
    ThriftClient.builder("http://127.0.0.1:8080")
                .path("/hello")
                .serializationFormat(ThriftSerializationFormats.JSON)
                .build(HelloService.Iface.class); // or AsyncIface.class

Since we specified HelloService.Iface as the client type, ThriftClients.newClient() will return a synchronous client implementation. If we specified HelloService.AsyncIface, the calling code would have looked like the following:

import com.linecorp.armeria.common.thrift.ThriftFuture;
import com.linecorp.armeria.common.util.CompletionActions;
import com.linecorp.armeria.client.thrift.ThriftClients;

HelloService.AsyncIface helloService =
    ThriftClients.newClient("http://127.0.0.1:8080/hello",
                            HelloService.AsyncIface.class);

ThriftFuture<String> future = new ThriftFuture<String>();
helloService.hello("Armerian World", future);

future.thenAccept(response -> assert response.equals("Hello, Armerian World!"))
      .exceptionally(cause -> {
          cause.printStackTrace();
          return null;
      });

// You can also wait until the call is finished.
String reply = future.get();

The example above introduces a new class called ThriftFuture. It is a subtype of Java 8 CompletableFuture_ that implements Thrift AsyncMethodCallback. Once passed as a callback of an asynchronous Thrift call, ThriftFuture will complete itself when the reply is received or the call fails. You'll find it way more convenient to consume the reply than AsyncMethodCallback thanks to the rich set of methods provided by CompletableFuture.

You can also use the builder pattern for client construction:

import com.linecorp.armeria.common.HttpRequest;
import com.linecorp.armeria.common.HttpResponse;

HelloService.Iface helloService =
    ThriftClients.builder("http://127.0.0.1:8080")
                 .path("/hello")
                 .responseTimeoutMillis(10000)
                 .decorator(LoggingClient.newDecorator())
                 .build(HelloService.Iface.class); // or AsyncIface.class

String greeting = helloService.hello("Armerian World");
assert greeting.equals("Hello, Armerian World!");

As you might have noticed already, we decorated the client using LoggingClient, which logs all requests and responses. You might be interested in decorating a client using other decorators, for example to gather metrics. Please also refer to ThriftClientBuilder for more configuration options.

See also