Как получить динамический базовый URL-адрес с помощью клиента Quarkus MicroProfile Rest?

Quarkus, использующий Rest Client, объясняет, как использовать REST-клиент MicroProfile. В качестве базового URL-адреса можно использовать application.properties.

org.acme.restclient.CountriesService/mp-rest/url=https://restcountries.eu/rest # 

При указанном выше подходе не может быть динамического базового URL.

Этого можно добиться с помощью RestClientBuilder, как описано в MicroProfile Rest Client. Обратной стороной этого подхода является отсутствие возможности автоматического согласования.

SimpleGetApi simpleGetApi = RestClientBuilder.newBuilder().baseUri(getApplicationUri()).build(SimpleGetApi.class);

Есть ли другой или лучший способ добиться этого? Спасибо.

2 ответа

Хотя это правда, что MP Rest CLient не позволяет вам динамически устанавливать BaseUri при использовании декларативных/инъекционных клиентов, есть несколько (хотя и хакерских) способов добиться этого.

Один из них — использовать стандартный ClientRequestFilterкоторый может изменить URL-адрес:

      @Provider
@Slf4j
public class Filter implements ClientRequestFilter {

  @Inject RequestScopeHelper helper;

  @Override
  public void filter(ClientRequestContext requestContext) throws IOException {
    if (helper.getUrl() != null) {
      URI newUri = URI.create(requestContext.getUri().toString().replace("https://originalhost.com", helper.getUrl()));
      requestContext.setUri(newUri);
    }
  }
}

Где RequestScopeHelper- это некоторый класс справки (например, bean-компонент запроса), через который вы можете передать динамический URL-адрес, например:

      @Inject
RequestScopeHelper helper;

@Inject
@RestClient
TestIface myApiClient;
 
public void callSomeAPIWithDynamicBaseUri(String dynamic) {
  helper.setUrl(dynamic);
  myApiClient.someMethod();
}

Во-вторых, использовать SPI остальных клиентов MP, а именно RestClientListener , который позволяет вам изменять остальные клиенты после их сборки.

Чтобы это работало, вы должны установить область действия вашего оставшегося клиента на RequestScopedтак что новый экземпляр создается для каждого запроса (например, если вы используете синглтон, тогда клиент создается только один раз, и ваш слушатель будет вызываться только один раз). Это вы можете сделать через свойства quarkus:

      quarkus.rest-client."com.example.MyRestIface".scope=javax.enterprise.context.RequestScoped
      public class MyListener implements RestClientListener {

  @Override
  public void onNewClient(Class<?> serviceInterface, RestClientBuilder builder) {
    String newUri = //obtain dynamic URI from somewhere e.g. again request scope bean lookup, or maybe dynamic config source (create new in-memory ConfigSource, before you invoke your rest client set the corresponding rest client url property to your dynamic value, then inside this listener use ConfigProvider.getConfig().getProperty...)
    builder.baseUri(URI.create(newUri));
  }
}

Не забудьте зарегистрировать этого слушателя в качестве поставщика услуг ( META-INF/services/org.eclipse.microprofile.rest.client.spi.RestClientListener)

Другой вариант — использовать собственный производитель CDI, который будет создавать для вас экземпляры клиента Rest; тогда вы могли бы контролировать всю конфигурацию клиента самостоятельно. Вы можете использовать RestClientBase из оставшегося клиента Quarkus , который Quarkus использует под капотом на этапе развертывания для создания экземпляров клиента. Однако вам придется дублировать всю логику, связанную с регистрацией обработчиков, перехватчиков и т. д.

Имейте в виду, что любое из этих решений усложнит отладку и анализ проблем, потому что теперь у вас будет несколько мест, где контролируется URI (свойства MP config/quarkus, env vars, ваша пользовательская реализация...), поэтому вам нужно быть осторожным с вашим подходом и, возможно, добавить некоторые явные сообщения журнала, когда вы переопределяете URI вручную.

Клиент MicroProfile REST в Quarkus позволяет вам использовать динамический базовый URL-адрес с помощью этого простого «хака»:

Просто поставьте пустойStringв@Pathаннотации для вашего интерфейса API:

      import javax.ws.rs.GET;
import javax.ws.rs.Path;

@Path("")
public interface SimpleGetApi {
    @Path("")
    @GET
    String callWithDynmamicUrl(); //it can be String or any return type you want
}

После этого вы готовы вызывать свой динамический базовый URL:

      import org.eclipse.microprofile.rest.client.RestClientBuilder;
import java.net.URI;

public class Example {

    public static void main(String[] args) {
        URI anyDynamicUrl = URI.create("http://restcountries.eu/rest/some/dynamic/path");
        SimpleGetApi simpleGetApi = RestClientBuilder.newBuilder().baseUri(anyDynamicUrl)
                .build(SimpleGetApi.class);
        simpleGetApi.callWithDynmamicUrl();
    }
}
Другие вопросы по тегам