Programming paradigms

As explained here ServiceTalk supports multiple programming paradigms for users to use. In this document we elaborate on how HTTP module provides support for these programming paradigms.

Server

An HTTP Server in ServiceTalk uses a user provided Service that implements all the business logic for that server. ServiceTalk allows users to write these Service implementations in different programming paradigms.

Blocking and Aggregated

This programming paradigm exposes the request (including the payload body) as a single aggregated object, and the response (including the payload body) is also a single aggregated object. The Service directly returns the response object and there are no asynchronous primitives involved.

HttpServers.forPort(8080)
  .listenBlockingAndAwait((ctx, request, responseFactory) ->
    responseFactory.ok().payloadBody("Hello World!", textSerializer()))
  .awaitShutdown();

Blocking and Streaming

This programming paradigm exposes the request payload body as an Iterable of Buffers and the response payload body is written via an HttpPayloadWriter or an HttpOutputStream. There are no asynchronous primitives involved.

HttpServers.forPort(8080).listenBlockingStreamingAndAwait((ctx, request, response) -> {
  try (HttpPayloadWriter<String> payloadWriter = response.sendMetaData(textSerializer())) {
    payloadWriter.write("Hello");
    payloadWriter.write(" World!");
  }
}).awaitShutdown();

Asynchronous and Aggregated

This programming paradigm exposes the request payload body as a single aggregated object, and the response payload body is also a single aggregated object. The Service provides the response by completing a Single which is an asynchronous primitive.

HttpServers.forPort(8080)
  .listenAndAwait((ctx, request, responseFactory) ->
    succeeded(responseFactory.ok().payloadBody("Hello World!", textSerializer())))
  .awaitShutdown();

Asynchronous and Streaming

This programming paradigm exposes the request payload body as a Publisher typically of Buffers (although other types like file regions may be added), the response meta-data is provided by completing a Single, and the response payload body is written via a Publisher.

HttpServers.forPort(8080)
  .listenStreamingAndAwait((ctx, request, responseFactory) ->
    succeeded(responseFactory.ok()
      .payloadBody(from("Hello", " World!"), textSerializer())))
  .awaitShutdown();

Client

An HTTP Client in ServiceTalk is used by users to send requests to a server. ServiceTalk allows users to create a Client for different programming paradigms.

Blocking and Aggregated

This programming paradigm expects the request (including the payload body) as a single aggregated object, and the response (including the payload body) is also a single aggregated object. The Client directly returns the response object and there are no asynchronous primitives involved.

try (BlockingHttpClient client = HttpClients.forSingleAddress("localhost", 8080).buildBlocking()) {
  HttpResponse response = client.request(client.get("/sayHello"));
  // use the response
}

Blocking and Streaming

This programming paradigm expects the request payload body as an Iterable of Buffers and the response payload body is consumed via an Iterable of Buffers. There are no asynchronous primitives involved.

try (BlockingStreamingHttpClient client = HttpClients.forSingleAddress("localhost", 8080)
      .buildBlockingStreaming()) {
  BlockingStreamingHttpResponse response = client.request(client.get("/sayHello"));
  System.out.println(response.toString((name, value) -> value));
  try (BlockingIterator<String> payload = response.payloadBody(textDeserializer()).iterator()) {
    while (payload.hasNext()) {
      System.out.println(payload.next());
    }
  }
}

Asynchronous and Aggregated

This programming paradigm expects the request payload body as a single aggregated object, and the response payload body is also a single aggregated object. The HttpClient provides the response via a Single which is an asynchronous primitive.

try (HttpClient client = HttpClients.forSingleAddress("localhost", 8080).build()) {
// This example is demonstrating asynchronous execution, but needs to prevent the main
// thread from exiting before the response has been processed. This isn't typical usage
// for a streaming API but is useful for demonstration purposes.
  CountDownLatch responseProcessedLatch = new CountDownLatch(1);
  client.request(client.get("/sayHello"))
        .doFinally(responseProcessedLatch::countDown)
        .subscribe(resp -> {
     System.out.println(resp.toString((name, value) -> value));
     System.out.println(resp.payloadBody(textDeserializer()));
  });

  responseProcessedLatch.await();
}

Asynchronous and Streaming

This programming paradigm expects the request payload body as a Publisher typically of Buffers (although other types like file regions may be added), the response meta-data is provided via a Single, and the response payload body is written via a Publisher.

try (StreamingHttpClient client = HttpClients.forSingleAddress("localhost", 8080).buildStreaming()) {
// This example is demonstrating asynchronous execution, but needs to prevent the main thread from
// exiting before the response has been processed. This isn't typical usage for a streaming API but
// is useful for demonstration purposes.
  CountDownLatch responseProcessedLatch = new CountDownLatch(1);
  client.request(client.get("/sayHello"))
        .beforeOnSuccess(response -> System.out.println(response.toString((name, value) -> value)))
        .flatMapPublisher(resp -> resp.payloadBody(textDeserializer()))
        .doFinally(responseProcessedLatch::countDown)
        .forEach(System.out::println);

  responseProcessedLatch.await();
}