0

I searched for a bit but couldn't find an "Armeria API" to do this elegantly. I'm familiar with Netty so for the time being I'm using QueryStringEncoder. Is there a better way to do this ? Here I have a dynamic Map of params and I need to build the HTTP client programmatically. The Armeria WebClient and RequestHeaders builders provide ways to add headers and path, but not query string parameters.

    HttpMethod httpMethod = HttpMethod.valueOf('GET');
    String url = 'http://example.com'
    String path = '/foo';
    if (params != null) {
        QueryStringEncoder qse = new QueryStringEncoder(url + path);
        params.forEach((k, v) -> {
            if (v != null) {
                v.forEach(s -> qse.addParam(k, s));
            }
        });            
        try {
            URI uri = qse.toUri();
            path = path + "?" + uri.getRawQuery();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    WebClient webClient = WebClient.builder(url).decorator(new HttpClientLogger()).build();
    RequestHeadersBuilder rhb = RequestHeaders.builder(httpMethod, path);
Peter Thomas
  • 54,465
  • 21
  • 84
  • 248

1 Answers1

3

Armeria has QueryParams for building or parsing a query string:

// You don't really need a Map to build a QueryParams.
// See QueryParams.of() or QueryParamsBuilder.add() for more information.
Map<String, String> paramMap = ...;
QueryParams params =
    QueryParams.builder()
               .add(paramMap)
               .build();

WebClient client =
    WebClient.builder("http://example.com")
             .decorator(...)
             .build();

AggregatedHttpResponse res =
    client.get("/foo?" + params.toQueryString()).aggregate().join()

You might also find Cookie useful.

trustin
  • 12,231
  • 6
  • 42
  • 52
  • 1
    @Peter Please let us know if you have any inconveniences or a room for improvements (even a tiny one) while working with the `QueryParams` API. – trustin Aug 31 '20 at 03:34
  • I will certainly do that ! I'm a huge fan of netty and now beginning to use armeria. I have a question which I don't mind asking separately if needed, but Trustin - have you ever seen the need for multi-value headers in the wild ? if not, I won't even bother supporting headers as `Map>` in my code (which is meant as "platform" code) - and will just stick to `Map` – Peter Thomas Aug 31 '20 at 03:54
  • 1
    @Peter Thanks for giving Armeria a try! Let me look forward to your feed back ;-) For headers, you can just use Armeria's `HttpHeaders` type. In Guava, there's a class called `Multimap`. Multi-value headers are often used for setting cookies, so I'd say it's pretty common. – trustin Sep 01 '20 at 02:17
  • ah yes, cookies. thanks Trustin. regarding the `QueryParams` I was honestly expecting an API on the `WebClientBuilder` to do `queryParam(name, value)` - is there a reason why this is not the case, I'm sure I'll learn more from your answer. – Peter Thomas Sep 01 '20 at 03:24
  • 1
    @Peter It's because a query string is usually not a part of a base URL. A base URL, which is specified when you create a `WebClient`, is something that does not change, e.g. `https://example.com`, so you can create a `WebClient` instance and reuse it many times with other changing parts, e.g. `/foo?bar=2`. I think it might be useful to provide a way to add query parameters when building a request, though. Let me add about this to https://github.com/line/armeria/issues/2390 Thanks! – trustin Sep 01 '20 at 08:43
  • understood ! maybe you should just accept an instance of `QueryParams` for e.g. `webClient.post("/upload", qp, "{ \"foo\": \"bar\" }")`, yes it is extra clunky, but it will help those new to the framework to be "aware" of this helper. a compromise would be to add `queryParam()` to `RequestHeadersBuilder`. thanks for answering my questions, and I have subscribed to that git issue. – Peter Thomas Sep 01 '20 at 08:56
  • 1
    @PeterThomas Cool! Thanks for the ideas. Let me add it to the GitHub issue. The goal is to make `WebClient` API a lot more convenient to use than it is now. Please feel free to leave more comments about what you'd like to see from our `WebClient` API or what existing HTTP client library you preferred. – trustin Sep 01 '20 at 09:06