Skip to main content

Calling an HTTP service

You can create a WebClient with a base URI and send a request with a relative path.

import com.linecorp.armeria.client.WebClient;
import com.linecorp.armeria.common.AggregatedHttpResponse;
import com.linecorp.armeria.common.HttpHeaderNames;
import com.linecorp.armeria.common.HttpMethod;
import com.linecorp.armeria.common.RequestHeaders;

WebClient webClient = WebClient.of("http://example.com/");

// Send a simple GET request.
AggregatedHttpResponse res1 = webClient.get("/foo/bar.txt").aggregate().join();

// Send a GET request with an additional header.
RequestHeaders getJson = RequestHeaders.of(HttpMethod.GET, "/foo/bar.json",
HttpHeaderNames.ACCEPT, "application/json");

AggregatedHttpResponse res2 = webClient.execute(getJson).aggregate().join();

// Send a simple POST request encoded in UTF-8.
AggregatedHttpResponse res3 = webClient.post("/upload", "{ \"foo\": \"bar\" }")
.aggregate().join();

You can also create a WebClient without a base URI and send a request with an absolute URI. The ad-hoc WebClient would be useful in the following cases:

  • Sending requests to arbitrary endpoints
  • Building a proxy server
  • Handling redirected requests
import com.linecorp.armeria.common.HttpStatus;
import com.linecorp.armeria.common.HttpHeaderNames;

// Create a WebClient without a base URI.
WebClient webClient = WebClient.of();

// Send a request with an absolute URI.
AggregatedHttpResponse res1 = webClient.get("http://example.com/foo/bar.txt")
.aggregate()
.join();

// Send a GET request with an authority header.
HttpRequest request = HttpRequest.of(RequestHeaders.builder()
.scheme(SessionProtocol.HTTP)
.authority("example.com")
.method(HttpMethod.GET)
.path("/foo/bar.txt")
.build());
AggregatedHttpResponse res2 = webClient.execute(request).aggregate().join();

// Handle a redirected request
AggregatedHttpResponse redirected = webClient.get("http://example.com/redirect")
.aggregate()
.join();
assert redirected.status() == HttpStatus.TEMPORARY_REDIRECT;
String location = redirected.headers().get(HttpHeaderNames.LOCATION);
AggregatedHttpResponse actual = webClient.get(location).aggregate().join();

Decorating a WebClient

You can enrich your WebClient by decorating it with decorators. A decorator wraps another client to intercept an outgoing request or an incoming response. A lot of core features such as logging, metrics and distributed tracing are implemented as decorators.

import brave.http.HttpTracing;
import com.linecorp.armeria.client.brave.BraveClient;
import com.linecorp.armeria.client.circuitbreaker.CircuitBreaker;
import com.linecorp.armeria.client.circuitbreaker.CircuitBreakerClient;
import com.linecorp.armeria.client.circuitbreaker.CircuitBreakerRule;
import com.linecorp.armeria.client.cookie.CookieClient;
import com.linecorp.armeria.client.encoding.DecodingClient;
import com.linecorp.armeria.client.limit.ConcurrencyLimitingClient;
import com.linecorp.armeria.client.logging.ContentPreviewingClient;
import com.linecorp.armeria.client.logging.LoggingClient;
import com.linecorp.armeria.client.metric.MetricCollectingClient;
import com.linecorp.armeria.client.retry.RetryRule;
import com.linecorp.armeria.client.retry.RetryingClient;
import com.linecorp.armeria.common.metric.MeterIdPrefixFunction;

HttpTracing tracing = ...;
WebClient.builder()
.decorator(BraveClient.newDecorator(tracing))
.decorator(CircuitBreakerClient.newDecorator(
CircuitBreaker.ofDefaultName(), CircuitBreakerRule.onServerErrorStatus()))
.decorator(ConcurrencyLimitingClient.newDecorator(64))
.decorator(ContentPreviewingClient.newDecorator(128))
.decorator(CookieClient.newDecorator())
.decorator(DecodingClient.newDecorator())
.decorator(MetricCollectingClient.newDecorator(
MeterIdPrefixFunction.ofDefault("armeria.client")))
.decorator(LoggingClient.newDecorator())
.decorator(RetryingClient.newDecorator(RetryRule.onUnprocessed()))
...
.build();

Please see Decorating a client to learn how it works.

Service discovery with WebClient

Armeria provides the various service discovery mechanisms with EndpointGroup, from Kubernetes-style DNS records to Consul. Requests are sent to dynamically retrieved Endpoints by specifying an EndpointGroup to a WebClient.

import com.linecorp.armeria.client.endpoint.dns.DnsServiceEndpointGroup;

// Retrieve the Endpoint list from SRV records
DnsServiceEndpointGroup group =
DnsServiceEndpointGroup.of("k8s.default.svc.cluster.local.");

// Filter out unhealthy endpoints
HealthCheckedEndpointGroup healthCheckedGroup =
HealthCheckedEndpointGroup.of(group, "/monitor/l7check");

WebClient.builder(SessionProtocol.HTTP, healthCheckedGroup)
...
.build();

Please check Client-side load balancing and service discovery for more information.

Configuring ClientFactory

A ClientFactory manages connections and protocol-specific properties. You can build your own ClientFactory using ClientFactoryBuilder and set it through WebClientBuilder.factory().

import com.linecorp.armeria.client.ClientFactory;
// Create a customized ClientFactory
ClientFactory clientFactory =
ClientFactory.builder()
// Increase the connect timeout from 3.2s to 10s.
.connectTimeout(Duration.ofSeconds(10))
.
.build();

WebClient client =
WebClient.builder()
.factory(clientFactory)
.build();

Please check Customizing a ClientFactory with ClientFactoryBuilder for the details.

See also

Like Armeria?
Star us ⭐️

×