Фильтры REST-клиента Quarkus: Полное руководство по регистрации
Узнайте, как автоматически регистрировать ClientRequestFilter и ClientResponseFilter в расширениях Quarkus при миграции с quarkus-resteasy на quarkus-rest. Найдите эквивалентный BuildItem для фильтров на стороне клиента в Quarkus 3.27 и реализуйте автоматическую регистрацию фильтров во всех REST-клиентах.
Как автоматически регистрировать ClientRequestFilter и ClientResponseFilter в расширении Quarkus при миграции с quarkus-resteasy на quarkus-rest? Я успешно использовал ContainerRequestFilterBuildItem и ContainerResponseFilterBuildItem для серверных фильтров, но мне нужен эквивалентный BuildItem для клиентских фильтров в Quarkus 3.27. Ранее с quarkus-resteasy я использовал ResteasyJaxrsProviderBuildItem для автоматической регистрации всех фильтров. Фильтры работают при ручном включении с помощью @RegisterRestClient, но я хочу, чтобы расширение автоматически регистрировало их во всех REST-клиентах.
Разработка расширений Quarkus: ClientRequestFilterBuildItem и ClientResponseFilterBuildItem
При разработке расширений для Quarkus, особенно работающих с Quarkus REST (ранее RESTEasy), часто возникает необходимость работать с фильтрами HTTP-запросов и ответов. В этом контексте два важных BuildItem - ClientRequestFilterBuildItem и ClientResponseFilterBuildItem - играют ключевую роль.
ClientRequestFilterBuildItem
ClientRequestFilterBuildItem используется для регистрации фильтров, которые будут применяться к исходящим HTTP-запросам при использовании Quarkus REST клиентских возможностей.
Основные сценарии использования:
- Добавление заголовков ко всем исходящим запросам
- Логирование исходящих запросов
- Аутентификация и авторизация
- Модификация запросов перед отправкой
Пример использования:
import io.quarkus.builder.item.BuildItem;
import io.quarkus.rest.client.reactive.ClientRequestFilterBuildItem;
public class MyClientRequestFilterBuildItem implements BuildItem {
private final Class<?> filterClass;
public MyClientRequestFilterBuildItem(Class<?> filterClass) {
this.filterClass = filterClass;
}
public Class<?> getFilterClass() {
return filterClass;
}
}
Регистрация фильтра:
@BuildStep
ClientRequestFilterBuildItem registerClientRequestFilter() {
return new ClientRequestFilterBuildItem(MyClientRequestFilter.class);
}
ClientResponseFilterBuildItem
ClientResponseFilterBuildItem используется для регистрации фильтров, которые будут обрабатывать входящие HTTP-ответы от REST-клиентов.
Основные сценарии использования:
- Обработка ошибок ответа
- Логирование входящих ответов
- Парсинг и преобразование ответов
- Обработка особых статусов ответа
Пример использования:
import io.quarkus.builder.item.BuildItem;
import io.quarkus.rest.client.reactive.ClientResponseFilterBuildItem;
public class MyClientResponseFilterBuildItem implements BuildItem {
private final Class<?> filterClass;
public MyClientResponseFilterBuildItem(Class<?> filterClass) {
this.filterClass = filterClass;
}
public Class<?> getFilterClass() {
return filterClass;
}
}
Регистрация фильтра:
@BuildStep
ClientResponseFilterBuildItem registerClientResponseFilter() {
return new ClientResponseFilterBuildItem(MyClientResponseFilter.class);
}
Полный пример расширения
Вот полный пример расширения, которое регистрирует как фильтр запросов, так и фильтр ответов:
import io.quarkus.arc.deployment.AdditionalBeanBuildItem;
import io.quarkus.builder.BuildStep;
import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.rest.client.reactive.ClientRequestFilterBuildItem;
import io.quarkus.rest.client.reactive.ClientResponseFilterBuildItem;
public class MyRestClientExtension {
@BuildStep
AdditionalBeanBuildItem registerMyFilters() {
return AdditionalBeanBuildItem.builder()
.addBeanClass(MyClientRequestFilter.class)
.addBeanClass(MyClientResponseFilter.class)
.build();
}
@BuildStep
ClientRequestFilterBuildItem registerClientRequestFilter(BuildProducer<ClientRequestFilterBuildItem> producer) {
return producer.create(MyClientRequestFilter.class);
}
@BuildStep
ClientResponseFilterBuildItem registerClientResponseFilter(BuildProducer<ClientResponseFilterBuildItem> producer) {
return producer.create(MyClientResponseFilter.class);
}
}
Примеры фильтров
Фильтр запросов:
import org.jboss.resteasy.reactive.client.spi.ResteasyReactiveClientRequestContext;
import org.jboss.resteasy.reactive.client.spi.ResteasyReactiveClientRequestFilter;
import jakarta.annotation.Priority;
import jakarta.ws.rs.Priorities;
@Priority(Priorities.AUTHENTICATION)
public class MyClientRequestFilter implements ResteasyReactiveClientRequestFilter {
@Override
public void filter(ResteasyReactiveClientRequestContext context) {
// Добавляем кастомный заголовок ко всем запросам
context.getHeaders().add("X-Request-ID", generateRequestId());
// Логируем исходящий запрос
System.out.println("Sending request to: " + context.getUri());
}
private String generateRequestId() {
return java.util.UUID.randomUUID().toString();
}
}
Фильтр ответов:
import org.jboss.resteasy.reactive.client.spi.ResteasyReactiveClientResponseContext;
import org.jboss.resteasy.reactive.client.spi.ResteasyReactiveClientResponseFilter;
import jakarta.annotation.Priority;
import jakarta.ws.rs.Priorities;
import jakarta.ws.rs.core.Response;
@Priority(Priorities.USER)
public class MyClientResponseFilter implements ResteasyReactiveClientResponseFilter {
@Override
public void filter(ResteasyReactiveClientResponseContext context) {
// Проверяем статус ответа
if (context.getStatus() >= 400) {
System.out.println("Error response received: " + context.getStatus());
}
// Логируем входящий ответ
System.out.println("Received response with status: " + context.getStatus());
}
}
Настройка через application.properties
Вы можете настроить поведение фильтров через файл application.properties:
# Включение или отключение фильтров
my.rest.client.request-filter.enabled=true
my.rest.client.response-filter.enabled=true
# Настройка параметров фильтров
my.rest.client.request-header=X-Custom-Header
my.rest.client.log-requests=true
Тестирование расширения
Для тестирования вашего расширения с фильтрами можно использовать интеграционные тесты:
import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Test;
import jakarta.inject.Inject;
import jakarta.ws.rs.client.Client;
import jakarta.ws.rs.client.ClientBuilder;
import jakarta.ws.rs.core.Response;
import static org.junit.jupiter.api.Assertions.assertEquals;
@QuarkusTest
public class MyRestClientExtensionTest {
@Inject
Client client;
@Test
public void testClientRequestFilter() {
Response response = client.target("/test-endpoint")
.request()
.get();
assertEquals(200, response.getStatus());
// Дополнительные проверки для фильтров
}
}
Заключение
ClientRequestFilterBuildItem и ClientResponseFilterBuildItem являются мощными инструментами при разработке расширений Quarkus для работы с REST-клиентами. Они позволяют гибко настраивать обработку как исходящих запросов, так и входящих ответов, что особенно полезно для кросс-забоченностей таких как аутентификация, логирование, обработка ошибок и т.д.
Правильное использование этих BuildItem обеспечивает интеграцию ваших фильтров в экосистему Quarkus REST и позволяет создавать переиспользуемые и конфигурируемые компоненты для ваших приложений.