A light weight wrapper to the JDK 11+ Java Http Client
- Adds a fluid API for request constructing URL and payload
- Adds JSON marshalling/unmarshalling of request and response using Jackson or Gson
- Adds request/response logging
<dependency>
<groupId>io.avaje</groupId>
<artifactId>avaje-http-client</artifactId>
<version>1.6</version>
</dependency>
Create a HttpClientContext with a baseUrl, Jackson or Gson based JSON body adapter, logger.
public HttpClientContext client() {
return HttpClientContext.newBuilder()
.withBaseUrl(baseUrl)
.withRequestListener(new RequestLogger())
.withBodyAdapter(new JacksonBodyAdapter(new ObjectMapper()))
// .withBodyAdapter(new GsonBodyAdapter(new Gson()))
.build();
}
From HttpClientContext:
- Create a request
- Build the url via path(), matrixParam(), queryParam()
- Optionally set headers(), cookies() etc
- Optionally specify a request body (JSON, form, or raw BodyPublisher)
- Http verbs - GET(), POST(), PUT(), PATCH(), DELETE(), HEAD(), TRACE()
- Optionally return response body as a bean, list of beans, or raw
GET as String
HttpResponse<String> hres = clientContext.request()
.path("hello")
.GET()
.asString();
GET as json to single bean
Customer customer = clientContext.request()
.path("customers").path(42)
.GET()
.bean(Customer.class);
GET as json to a list of beans
List<Customer> list = clientContext.request()
.path("customers")
.GET()
.list(Customer.class);
GET as application/x-json-stream
as a stream of beans
Stream<Customer> stream = clientContext.request()
.path("customers/all")
.GET()
.stream(Customer.class);
POST a bean as json request body
HelloDto bean = new HelloDto(12, "rob", "other");
HttpResponse<Void> res = clientContext.request()
.path("hello/savebean")
.body(bean)
.POST()
.asDiscarding();
assertThat(res.statusCode()).isEqualTo(201);
Path
HttpResponse<String> res = clientContext.request()
.path("customers")
.path("42")
.path("contacts")
.GET()
.asString();
// is the same as ...
HttpResponse<String> res = clientContext.request()
.path("customers/42/contacts")
.GET()
.asString();
MatrixParam
HttpResponse<String> httpRes = clientContext.request()
.path("books")
.matrixParam("author", "rob")
.matrixParam("country", "nz")
.path("foo")
.matrixParam("extra", "banana")
.GET().asString();
QueryParam
List<Product> beans = clientContext.request()
.path("products")
.queryParam("sortBy", "name")
.queryParam("maxCount", "100")
.GET().list(Product.class);
FormParam
HttpResponse<Void> res = clientContext.request()
.path("register/user")
.formParam("name", "Bazz")
.formParam("email", "user@foo.com")
.formParam("url", "http://foo.com")
.formParam("startDate", "2020-12-03")
.POST()
.asDiscarding();
assertThat(res.statusCode()).isEqualTo(201);
Built in support for obtaining and setting an Authorization token.
class MyAuthTokenProvider implements AuthTokenProvider {
@Override
public AuthToken obtainToken(HttpClientRequest tokenRequest) {
AuthTokenResponse res = tokenRequest
.url("https://foo/v2/token")
.header("content-type", "application/json")
.body(authRequestAsJson())
.POST()
.bean(AuthTokenResponse.class);
Instant validUntil = Instant.now().plusSeconds(res.expires_in).minusSeconds(60);
return AuthToken.of(res.access_token, validUntil);
}
}
HttpClientContext ctx = HttpClientContext.newBuilder()
.withBaseUrl("https://foo")
.withBodyAdapter(new JacksonBodyAdapter(objectMapper))
.withRequestListener(new RequestLogger())
.withAuthTokenProvider(new MyAuthTokenProvider()) <!-- HERE
.build();
Now all requests using the HttpClientContext will automatically get
an Authorization
header with Bearer
token added. The token will be
obtained when necessary.