or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

dsl-api.mdinbound-endpoints.mdindex.mdoutbound-endpoints.mdxml-configuration.md
tile.json

outbound-endpoints.mddocs/

Outbound Endpoints

Outbound endpoints execute HTTP requests reactively using Spring WebFlux's WebClient. They act as the client-side component, making HTTP calls to external services from within integration flows.

Key Information for Agents

Required Dependencies:

  • spring-webflux must be on classpath (provides WebClient)
  • spring-integration-core is required
  • reactor-core is required (provided transitively)

Default Behaviors:

  • extractPayload=true by default (extracts body from ResponseEntity)
  • extractRequestPayload=true by default (extracts payload from Message)
  • replyPayloadToFlux=false by default (resolves Mono to single value)
  • Default HTTP method: POST
  • Default charset: UTF-8
  • No cookie transfer by default
  • Default encoding mode: TEMPLATE_AND_VALUES

Threading Model:

  • All operations are non-blocking and execute on reactive scheduler threads
  • No thread blocking during HTTP I/O operations
  • Backpressure is properly handled through reactive streams
  • Reactor Context is propagated through message headers

Lifecycle:

  • Handlers are message handlers that process messages from channels
  • Lifecycle managed by Spring Integration infrastructure
  • autoStartup=true by default

Exceptions:

  • WebClientException - WebClient request failures
  • WebClientResponseException - HTTP response errors (4xx, 5xx)
  • HttpServerErrorException - 5xx server errors
  • HttpClientErrorException - 4xx client errors
  • HttpMessageNotReadableException - response body conversion failures
  • TimeoutException - request timeout errors

Edge Cases:

  • Empty request body: sends request without body
  • Empty response body: payload is null or empty Mono
  • Publisher payloads (Flux/Mono) require publisherElementType configuration
  • URI variables not provided: IllegalArgumentException at runtime
  • If extractPayload=false, full ResponseEntity is available in message payload
  • If replyPayloadToFlux=true, response is always Flux even for single values
  • Network errors: wrapped in WebClientException

Overview

Spring Integration WebFlux provides two types of outbound endpoints:

  • Outbound Channel Adapters - One-way endpoints that make HTTP requests without expecting integration flow to continue (fire-and-forget pattern)
  • Outbound Gateways - Request-reply endpoints that make HTTP requests and route responses back into the integration flow

Both types use WebClient for fully reactive, non-blocking HTTP communication.

Capabilities

Creating Outbound Gateways

Create outbound gateways that make HTTP requests and route responses back into the flow.

/**
 * Create an outbound gateway with a fixed URI.
 * @param uri - Target URI as String
 * @return WebFluxMessageHandlerSpec for fluent configuration
 */
public static WebFluxMessageHandlerSpec outboundGateway(String uri)

/**
 * Create an outbound gateway with a fixed URI and custom WebClient.
 * @param uri - Target URI as String
 * @param webClient - Custom configured WebClient instance
 * @return WebFluxMessageHandlerSpec for fluent configuration
 */
public static WebFluxMessageHandlerSpec outboundGateway(
    String uri,
    WebClient webClient)

/**
 * Create an outbound gateway with dynamic URI evaluation.
 * @param uriFunction - Function to compute URI from message
 * @return WebFluxMessageHandlerSpec for fluent configuration
 */
public static <P> WebFluxMessageHandlerSpec outboundGateway(
    Function<Message<P>, ?> uriFunction)

/**
 * Create an outbound gateway with dynamic URI evaluation via SpEL.
 * @param uriExpression - SpEL expression to evaluate URI
 * @return WebFluxMessageHandlerSpec for fluent configuration
 */
public static WebFluxMessageHandlerSpec outboundGateway(Expression uriExpression)

Usage Examples:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.dsl.IntegrationFlow;
import org.springframework.integration.webflux.dsl.WebFlux;
import org.springframework.http.HttpMethod;
import org.springframework.web.reactive.function.client.WebClient;

@Configuration
public class OutboundGatewayConfig {

    // Fixed URI
    @Bean
    public IntegrationFlow simpleOutboundFlow() {
        return IntegrationFlow
            .from("requestChannel")
            .handle(WebFlux.outboundGateway("https://api.example.com/users")
                .httpMethod(HttpMethod.GET)
                .expectedResponseType(User[].class))
            .channel("responseChannel")
            .get();
    }

    // Dynamic URI with function
    @Bean
    public IntegrationFlow dynamicUriFlow() {
        return IntegrationFlow
            .from("requestChannel")
            .handle(WebFlux.outboundGateway(
                message -> "https://api.example.com/users/" + message.getPayload()))
            .get();
    }

    // Custom WebClient
    @Bean
    public IntegrationFlow customClientFlow(WebClient customWebClient) {
        return IntegrationFlow
            .from("requestChannel")
            .handle(WebFlux.outboundGateway("https://api.example.com/data", customWebClient)
                .httpMethod(HttpMethod.GET))
            .get();
    }
}

Creating Outbound Channel Adapters

Create outbound channel adapters for one-way HTTP requests.

/**
 * Create an outbound channel adapter with a fixed URI.
 * Fire-and-forget pattern - doesn't route HTTP response back to flow.
 * @param uri - Target URI as String
 * @return WebFluxMessageHandlerSpec for fluent configuration
 */
public static WebFluxMessageHandlerSpec outboundChannelAdapter(String uri)

/**
 * Create an outbound channel adapter with custom WebClient.
 * @param uri - Target URI as String
 * @param webClient - Custom configured WebClient instance
 * @return WebFluxMessageHandlerSpec for fluent configuration
 */
public static WebFluxMessageHandlerSpec outboundChannelAdapter(
    String uri,
    WebClient webClient)

/**
 * Create an outbound channel adapter with dynamic URI.
 * @param uriFunction - Function to compute URI from message
 * @return WebFluxMessageHandlerSpec for fluent configuration
 */
public static <P> WebFluxMessageHandlerSpec outboundChannelAdapter(
    Function<Message<P>, ?> uriFunction)

/**
 * Create an outbound channel adapter with dynamic URI via SpEL.
 * @param uriExpression - SpEL expression to evaluate URI
 * @return WebFluxMessageHandlerSpec for fluent configuration
 */
public static WebFluxMessageHandlerSpec outboundChannelAdapter(Expression uriExpression)

Usage Example:

@Bean
public IntegrationFlow notificationFlow() {
    return IntegrationFlow
        .from("notificationChannel")
        .handle(WebFlux.outboundChannelAdapter("https://webhook.site/notify")
            .httpMethod(HttpMethod.POST)
            .expectedResponseType(Void.class))
        .get();
}

HTTP Method Configuration

Specify the HTTP method for the request.

/**
 * Set the HTTP method for the request.
 * @param httpMethod - HttpMethod (GET, POST, PUT, DELETE, PATCH, etc.)
 * @return Spec for method chaining
 */
public WebFluxMessageHandlerSpec httpMethod(HttpMethod httpMethod)

/**
 * Set the HTTP method using a SpEL expression.
 * @param httpMethodExpression - Expression object evaluating to HttpMethod
 * @return Spec for method chaining
 */
public WebFluxMessageHandlerSpec httpMethodExpression(Expression httpMethodExpression)

/**
 * Set the HTTP method using a function.
 * @param httpMethodFunction - Function returning HttpMethod
 * @return Spec for method chaining
 */
public <P> WebFluxMessageHandlerSpec httpMethodFunction(
    Function<Message<P>, HttpMethod> httpMethodFunction)

Usage Example:

import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;

@Bean
public IntegrationFlow dynamicMethodFlow() {
    return IntegrationFlow
        .from("requestChannel")
        .handle(WebFlux.outboundGateway("https://api.example.com/resource")
            .httpMethod(HttpMethod.POST))
        .get();
}

@Bean
public IntegrationFlow dynamicMethodExpressionFlow() {
    SpelExpressionParser parser = new SpelExpressionParser();
    return IntegrationFlow
        .from("requestChannel")
        .handle(WebFlux.outboundGateway("https://api.example.com/resource")
            .httpMethodExpression(parser.parseExpression("headers.httpMethod")))
        .get();
}

@Bean
public IntegrationFlow dynamicMethodFunctionFlow() {
    return IntegrationFlow
        .from("requestChannel")
        .handle(WebFlux.outboundGateway("https://api.example.com/resource")
            .httpMethodFunction(message -> 
                message.getHeaders().get("httpMethod", HttpMethod.class)))
        .get();
}

Expected Response Type

Specify the expected response type for deserialization.

/**
 * Set the expected response type.
 * @param expectedResponseType - Java class for response deserialization
 * @return Spec for method chaining
 */
public WebFluxMessageHandlerSpec expectedResponseType(Class<?> expectedResponseType)

/**
 * Set the expected response type using ParameterizedTypeReference for generics.
 * @param expectedResponseType - ParameterizedTypeReference for generic types
 * @return Spec for method chaining
 */
public WebFluxMessageHandlerSpec expectedResponseType(
    ParameterizedTypeReference<?> expectedResponseType)

/**
 * Set the expected response type using a SpEL expression.
 * @param expectedResponseTypeExpression - Expression object evaluating to Class or ParameterizedTypeReference
 * @return Spec for method chaining
 */
public WebFluxMessageHandlerSpec expectedResponseTypeExpression(
    Expression expectedResponseTypeExpression)

/**
 * Set the expected response type using a function.
 * @param expectedResponseTypeFunction - Function returning Class or ParameterizedTypeReference
 * @return Spec for method chaining
 */
public <P> WebFluxMessageHandlerSpec expectedResponseTypeFunction(
    Function<Message<P>, ?> typeFunction)

Usage Examples:

import org.springframework.core.ParameterizedTypeReference;
import java.util.List;

// Simple type
@Bean
public IntegrationFlow simpleTypeFlow() {
    return IntegrationFlow
        .from("requestChannel")
        .handle(WebFlux.outboundGateway("https://api.example.com/user")
            .expectedResponseType(User.class))
        .get();
}

// Generic type
@Bean
public IntegrationFlow genericTypeFlow() {
    return IntegrationFlow
        .from("requestChannel")
        .handle(WebFlux.outboundGateway("https://api.example.com/users")
            .expectedResponseType(new ParameterizedTypeReference<List<User>>() {}))
        .get();
}

// Dynamic type using Expression
@Bean
public IntegrationFlow dynamicTypeFlow() {
    SpelExpressionParser parser = new SpelExpressionParser();
    return IntegrationFlow
        .from("requestChannel")
        .handle(WebFlux.outboundGateway("https://api.example.com/data")
            .expectedResponseTypeExpression(
                parser.parseExpression("headers.responseType")))
        .get();
}

// Dynamic type using Function
@Bean
public IntegrationFlow dynamicTypeFunctionFlow() {
    return IntegrationFlow
        .from("requestChannel")
        .handle(WebFlux.outboundGateway("https://api.example.com/data")
            .expectedResponseTypeFunction(message -> 
                message.getHeaders().get("responseType", Class.class)))
        .get();
}

URI Variables

Define URI path variables for dynamic URI construction.

/**
 * Add a URI variable with a static value.
 * @param variable - Variable name in URI template
 * @param value - Static value for the variable
 * @return Spec for method chaining
 */
public WebFluxMessageHandlerSpec uriVariable(String variable, Object value)

/**
 * Add a URI variable with a SpEL expression.
 * @param variable - Variable name in URI template
 * @param expression - SpEL expression to evaluate for the variable
 * @return Spec for method chaining
 */
public WebFluxMessageHandlerSpec uriVariable(String variable, String expression)

/**
 * Add a URI variable with an Expression object.
 * @param variable - Variable name in URI template
 * @param expression - Expression to evaluate for the variable
 * @return Spec for method chaining
 */
public WebFluxMessageHandlerSpec uriVariable(String variable, Expression expression)

/**
 * Set all URI variables using a SpEL expression that evaluates to a Map.
 * @param uriVariablesExpression - SpEL expression evaluating to Map<String, ?>
 * @return Spec for method chaining
 */
public WebFluxMessageHandlerSpec uriVariablesExpression(String uriVariablesExpression)

/**
 * Set all URI variables using an Expression that evaluates to a Map.
 * @param uriVariablesExpression - Expression evaluating to Map<String, ?>
 * @return Spec for method chaining
 */
public WebFluxMessageHandlerSpec uriVariablesExpression(Expression uriVariablesExpression)

Usage Examples:

@Bean
public IntegrationFlow uriVariableFlow() {
    return IntegrationFlow
        .from("requestChannel")
        .handle(WebFlux.outboundGateway("https://api.example.com/users/{id}/orders/{orderId}")
            .uriVariable("id", "headers.userId")
            .uriVariable("orderId", "payload.orderId")
            .httpMethod(HttpMethod.GET))
        .get();
}

@Bean
public IntegrationFlow uriVariablesMapFlow() {
    return IntegrationFlow
        .from("requestChannel")
        .handle(WebFlux.outboundGateway("https://api.example.com/users/{id}")
            .uriVariablesExpression("headers.uriVariables"))
        .get();
}

Request Headers

Configure HTTP request header mapping.

/**
 * Set a custom HeaderMapper for complete control over header mapping.
 * @param headerMapper - Custom HeaderMapper implementation
 * @return Spec for method chaining
 */
public WebFluxMessageHandlerSpec headerMapper(HeaderMapper<HttpHeaders> headerMapper)

/**
 * Specify which message headers to map to HTTP request headers.
 * Supports patterns like "X-*" (all X- headers), "!X-Secret-*" (exclude X-Secret-* headers).
 * @param patterns - Header name patterns
 * @return Spec for method chaining
 */
public WebFluxMessageHandlerSpec mappedRequestHeaders(String... patterns)

/**
 * Specify which HTTP response headers to map to message headers.
 * @param patterns - Header name patterns
 * @return Spec for method chaining
 */
public WebFluxMessageHandlerSpec mappedResponseHeaders(String... patterns)

Usage Examples:

import org.springframework.integration.http.support.DefaultHttpHeaderMapper;

// Filter which message headers map to HTTP headers
@Bean
public IntegrationFlow headerMappingFlow() {
    return IntegrationFlow
        .from("requestChannel")
        .handle(WebFlux.outboundGateway("https://api.example.com/data")
            .mappedRequestHeaders("X-*", "!X-Secret-*")  // Map X-* headers except X-Secret-*
            .mappedResponseHeaders("X-Response-*"))      // Map X-Response-* from response
        .get();
}

// Set custom headers using enrichHeaders before the outbound endpoint
@Bean
public IntegrationFlow customHeadersFlow() {
    return IntegrationFlow
        .from("requestChannel")
        .enrichHeaders(h -> h
            .header("Authorization", "Bearer token123")
            .headerExpression("X-Request-ID", 
                "T(java.util.UUID).randomUUID().toString()"))
        .handle(WebFlux.outboundGateway("https://api.example.com/data")
            .mappedRequestHeaders("Authorization", "X-Request-ID"))
        .get();
}

// Custom HeaderMapper for advanced control
@Bean
public IntegrationFlow customHeaderMapperFlow() {
    DefaultHttpHeaderMapper headerMapper = new DefaultHttpHeaderMapper();
    headerMapper.setOutboundHeaderNames("X-*", "Authorization");
    headerMapper.setInboundHeaderNames("X-Response-*");

    return IntegrationFlow
        .from("requestChannel")
        .handle(WebFlux.outboundGateway("https://api.example.com/data")
            .headerMapper(headerMapper))
        .get();
}

Important Note: Unlike some other Spring Integration endpoints, WebFlux outbound endpoints do not provide direct header() or headerExpression() methods. To set custom HTTP headers, use the .enrichHeaders() DSL method before the outbound endpoint, then use .mappedRequestHeaders() to control which message headers are mapped to HTTP headers.

Extract Payload

Control whether to extract the response payload or keep the full ResponseEntity.

/**
 * Set whether to extract the payload from the ResponseEntity.
 * Default is true.
 * @param extractPayload - true to extract payload, false to keep ResponseEntity
 * @return Spec for method chaining
 */
public WebFluxMessageHandlerSpec extractPayload(boolean extractPayload)

Usage Example:

import org.springframework.http.ResponseEntity;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.HttpHeaders;

@Bean
public IntegrationFlow fullResponseFlow() {
    return IntegrationFlow
        .from("requestChannel")
        .handle(WebFlux.outboundGateway("https://api.example.com/data")
            .extractPayload(false)) // Get full ResponseEntity with headers, status
        .handle((payload, headers) -> {
            ResponseEntity<?> response = (ResponseEntity<?>) payload;
            HttpStatusCode status = response.getStatusCode();
            HttpHeaders responseHeaders = response.getHeaders();
            Object body = response.getBody();
            return processFullResponse(status, responseHeaders, body);
        })
        .get();
}

Publisher Element Type

Specify the element type when sending reactive Publishers (Flux/Mono) as request body.

/**
 * Set the element type for Publisher request bodies.
 * Used when payload is Flux or Mono.
 * @param publisherElementType - Java class of Publisher elements
 * @return Spec for method chaining
 */
public WebFluxMessageHandlerSpec publisherElementType(Class<?> publisherElementType)

/**
 * Set the element type using ParameterizedTypeReference for generic types.
 * @param publisherElementType - ParameterizedTypeReference for Publisher elements
 * @return Spec for method chaining
 */
public WebFluxMessageHandlerSpec publisherElementType(
    ParameterizedTypeReference<?> publisherElementType)

/**
 * Set the element type dynamically using a function.
 * @param typeFunction - Function to determine element type from message
 * @return Spec for method chaining
 */
public <P> WebFluxMessageHandlerSpec publisherElementTypeFunction(
    Function<Message<P>, ?> typeFunction)

/**
 * Set the element type using a SpEL expression.
 * @param publisherElementTypeExpression - SpEL expression evaluating to Class
 * @return Spec for method chaining
 */
public WebFluxMessageHandlerSpec publisherElementTypeExpression(
    Expression publisherElementTypeExpression)

Usage Example:

import reactor.core.publisher.Flux;

@Bean
public IntegrationFlow publisherFlow() {
    return IntegrationFlow
        .from("streamChannel")
        .handle(WebFlux.outboundGateway("https://api.example.com/stream")
            .httpMethod(HttpMethod.POST)
            .publisherElementType(DataEvent.class)) // Payload is Flux<DataEvent>
        .get();
}

Reply Payload to Flux

Control whether to return the response as a Flux or resolve it to a single value.

/**
 * Set whether to return the reply payload as a Flux.
 * If true, returns Flux even for single-element responses.
 * If false (default), resolves Mono to single value.
 * @param replyPayloadToFlux - true to return Flux, false to resolve value
 * @return Spec for method chaining
 */
public WebFluxMessageHandlerSpec replyPayloadToFlux(boolean replyPayloadToFlux)

Usage Example:

import org.springframework.integration.dsl.IntegrationFlowDefinition;

@Bean
public IntegrationFlow fluxReplyFlow() {
    return IntegrationFlow
        .from("requestChannel")
        .handle(WebFlux.outboundGateway("https://api.example.com/stream")
            .replyPayloadToFlux(true)) // Always return Flux
        .split() // Split Flux elements into individual messages
        .channel("processChannel")
        .get();
}

Custom Body Extractor

Provide a custom BodyExtractor for low-level response processing.

/**
 * Set a custom BodyExtractor for extracting the response body.
 * Allows low-level access to ClientHttpResponse.
 * @param bodyExtractor - BodyExtractor instance
 * @return Spec for method chaining
 */
public WebFluxMessageHandlerSpec bodyExtractor(
    BodyExtractor<?, ? super ClientHttpResponse> bodyExtractor)

Usage Example:

import org.springframework.integration.webflux.support.ClientHttpResponseBodyExtractor;
import org.springframework.web.reactive.function.client.ClientHttpResponse;

@Bean
public IntegrationFlow customExtractorFlow() {
    return IntegrationFlow
        .from("requestChannel")
        .handle(WebFlux.outboundGateway("https://api.example.com/data")
            .bodyExtractor(new ClientHttpResponseBodyExtractor()))
        .handle((payload, headers) -> {
            ClientHttpResponse response = (ClientHttpResponse) payload;
            // Access raw response
            HttpStatusCode status = response.getStatusCode();
            HttpHeaders responseHeaders = response.getHeaders();
            return processRawResponse(response);
        })
        .get();
}

Encoding Mode

Configure URI encoding mode (only when WebClient is not provided externally).

/**
 * Set the URI encoding mode.
 * Only applies when WebClient is created internally.
 * @param encodingMode - EncodingMode (TEMPLATE_AND_VALUES, VALUES_ONLY, URI_COMPONENT, NONE)
 * @return Spec for method chaining
 */
public WebFluxMessageHandlerSpec encodingMode(
    DefaultUriBuilderFactory.EncodingMode encodingMode)

Usage Example:

import org.springframework.web.util.DefaultUriBuilderFactory;

@Bean
public IntegrationFlow encodingFlow() {
    return IntegrationFlow
        .from("requestChannel")
        .handle(WebFlux.outboundGateway("https://api.example.com/search?q={query}")
            .encodingMode(DefaultUriBuilderFactory.EncodingMode.VALUES_ONLY)
            .uriVariable("query", "payload.searchTerm"))
        .get();
}

Transfer Cookies

Enable automatic cookie transfer between requests.

/**
 * Enable or disable cookie transfer between requests.
 * @param transferCookies - true to transfer cookies, false otherwise
 * @return Spec for method chaining
 */
public WebFluxMessageHandlerSpec transferCookies(boolean transferCookies)

Usage Example:

@Bean
public IntegrationFlow cookieFlow() {
    return IntegrationFlow
        .from("loginChannel")
        .handle(WebFlux.outboundGateway("https://api.example.com/login")
            .httpMethod(HttpMethod.POST)
            .transferCookies(true))
        .handle(WebFlux.outboundGateway("https://api.example.com/protected")
            .transferCookies(true)) // Cookies from login are sent
        .get();
}

Custom WebClient Configuration

Configure WebClient with custom settings for advanced use cases.

import io.netty.channel.ChannelOption;
import reactor.netty.http.client.HttpClient;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
import java.time.Duration;

@Bean
public WebClient customWebClient() {
    return WebClient.builder()
        .baseUrl("https://api.example.com")
        .defaultHeader("User-Agent", "My Integration App")
        .defaultHeader("Accept", "application/json")
        .defaultCookie("session", "xyz123")
        .filter(ExchangeFilterFunction.ofRequestProcessor(
            clientRequest -> {
                // Custom request processing
                return Mono.just(clientRequest);
            }))
        .filter(ExchangeFilterFunction.ofResponseProcessor(
            clientResponse -> {
                // Custom response processing
                return Mono.just(clientResponse);
            }))
        .clientConnector(new ReactorClientHttpConnector(
            HttpClient.create()
                .responseTimeout(Duration.ofSeconds(10))
                .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000)
        ))
        .codecs(configurer -> {
            // Custom codecs
            configurer.defaultCodecs().maxInMemorySize(16 * 1024 * 1024);
        })
        .build();
}

@Bean
public IntegrationFlow customWebClientFlow(WebClient customWebClient) {
    return IntegrationFlow
        .from("requestChannel")
        .handle(WebFlux.outboundGateway("/resource/{id}", customWebClient)
            .uriVariable("id", "payload.id"))
        .get();
}

Working with Reactive Publishers

Sending Flux as Request Body

import reactor.core.publisher.Flux;
import org.springframework.messaging.MessageChannel;
import org.springframework.integration.channel.MessageChannels;

@Bean
public IntegrationFlow sendFluxFlow() {
    return IntegrationFlow
        .from("dataStreamChannel")
        .handle(WebFlux.outboundGateway("https://api.example.com/batch")
            .httpMethod(HttpMethod.POST)
            .publisherElementType(DataItem.class))
        .get();
}

@Bean
public MessageChannel dataStreamChannel() {
    return MessageChannels.flux().get();
}

// Send Flux as message payload
@Autowired
private MessageChannel dataStreamChannel;

public void streamData() {
    Flux<DataItem> dataStream = Flux.interval(Duration.ofSeconds(1))
        .map(i -> new DataItem(i))
        .take(100);

    dataStreamChannel.send(MessageBuilder.withPayload(dataStream).build());
}

Receiving Flux as Response

import org.springframework.core.ParameterizedTypeReference;

@Bean
public IntegrationFlow receiveFluxFlow() {
    return IntegrationFlow
        .from("requestChannel")
        .handle(WebFlux.outboundGateway("https://api.example.com/events")
            .httpMethod(HttpMethod.GET)
            .replyPayloadToFlux(true)
            .expectedResponseType(new ParameterizedTypeReference<Flux<Event>>() {}))
        .split()
        .handle("eventProcessor", "process")
        .get();
}

Error Handling

HTTP Status Code Handling

import org.springframework.http.ResponseEntity;
import org.springframework.web.reactive.function.client.WebClientResponseException;

@Bean
public IntegrationFlow errorHandlingFlow() {
    return IntegrationFlow
        .from("requestChannel")
        .handle(WebFlux.outboundGateway("https://api.example.com/risky")
            .extractPayload(false))
        .handle((payload, headers) -> {
            ResponseEntity<?> response = (ResponseEntity<?>) payload;
            if (response.getStatusCode().is2xxSuccessful()) {
                return response.getBody();
            } else if (response.getStatusCode().is4xxClientError()) {
                throw new BadRequestException("Client error: " + response.getStatusCode());
            } else {
                throw new ServiceException("Server error: " + response.getStatusCode());
            }
        })
        .get();
}

WebClient Error Handling

import org.springframework.web.reactive.function.client.ExchangeFilterFunction;

@Bean
public WebClient errorHandlingWebClient() {
    return WebClient.builder()
        .baseUrl("https://api.example.com")
        .filter(ExchangeFilterFunction.ofResponseProcessor(
            clientResponse -> {
                if (clientResponse.statusCode().is5xxServerError()) {
                    return clientResponse.bodyToMono(String.class)
                        .flatMap(body -> Mono.error(new ServerException("Server error: " + body)));
                }
                return Mono.just(clientResponse);
            }))
        .build();
}

Reactive Error Handling

import reactor.core.publisher.Mono;

@Bean
public IntegrationFlow reactiveErrorHandlingFlow() {
    return IntegrationFlow
        .from("requestChannel")
        .handle(WebFlux.outboundGateway("https://api.example.com/data")
            .expectedResponseType(Data.class))
        .handle((payload, headers) -> {
            if (payload instanceof WebClientResponseException) {
                WebClientResponseException ex = (WebClientResponseException) payload;
                return Mono.error(new CustomException(ex));
            }
            return Mono.just(payload);
        })
        .onErrorContinue((ex, data) -> {
            // Handle errors gracefully
            log.error("Error processing: {}", ex.getMessage());
        })
        .get();
}

Request Attributes

Set WebClient request attributes for advanced configuration.

/**
 * Set a SpEL expression that evaluates to a Map of request attributes.
 * @param attributeVariablesExpression - SpEL expression evaluating to Map
 * @return Spec for method chaining
 */
public WebFluxMessageHandlerSpec attributeVariablesExpression(
    Expression attributeVariablesExpression)

/**
 * Set a SpEL expression string that evaluates to a Map of request attributes.
 * @param attributeVariablesExpression - SpEL expression string evaluating to Map
 * @return Spec for method chaining
 */
public WebFluxMessageHandlerSpec attributeVariablesExpression(
    String attributeVariablesExpression)

Usage Example:

import org.springframework.expression.spel.standard.SpelExpressionParser;
import java.util.Map;
import java.time.Duration;

@Bean
public IntegrationFlow requestAttributesFlow() {
    SpelExpressionParser parser = new SpelExpressionParser();
    return IntegrationFlow
        .from("requestChannel")
        .enrichHeaders(h -> h.header("attributes", Map.of(
            "timeout", Duration.ofSeconds(30),
            "retries", 3
        )))
        .handle(WebFlux.outboundGateway("https://api.example.com/data")
            .attributeVariablesExpression(
                parser.parseExpression("headers.attributes")))
        .get();
}

Direct Bean Configuration

For advanced use cases, configure WebFluxRequestExecutingMessageHandler directly.

package org.springframework.integration.webflux.outbound;

/**
 * Direct bean configuration for WebFluxRequestExecutingMessageHandler.
 */
public class WebFluxRequestExecutingMessageHandler
       extends AbstractHttpRequestExecutingMessageHandler {
    /**
     * Create handler with fixed URI.
     */
    public WebFluxRequestExecutingMessageHandler(String uri);

    /**
     * Create handler with dynamic URI expression.
     */
    public WebFluxRequestExecutingMessageHandler(Expression uriExpression);

    /**
     * Create handler with custom WebClient.
     */
    public WebFluxRequestExecutingMessageHandler(String uri, WebClient webClient);

    // Configuration methods
    public void setReplyPayloadToFlux(boolean replyPayloadToFlux);
    public void setBodyExtractor(BodyExtractor<?, ?> bodyExtractor);
    public void setPublisherElementType(Class<?> publisherElementType);
    public void setPublisherElementTypeExpression(Expression expression);
    public void setAttributeVariablesExpression(Expression expression);
    public void setEncodingMode(DefaultUriBuilderFactory.EncodingMode encodingMode);
}

Usage Example:

import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.messaging.MessageChannel;

@Bean
@ServiceActivator(inputChannel = "outboundChannel")
public WebFluxRequestExecutingMessageHandler customOutboundHandler(
        WebClient customWebClient) {
    WebFluxRequestExecutingMessageHandler handler =
        new WebFluxRequestExecutingMessageHandler(
            "https://api.example.com/data",
            customWebClient);

    handler.setHttpMethod(HttpMethod.POST);
    handler.setExpectedResponseType(ResponseData.class);
    handler.setReplyPayloadToFlux(false);

    return handler;
}

Types

package org.springframework.integration.webflux.dsl;

/**
 * Spec builder for configuring WebFlux outbound message handlers.
 */
public class WebFluxMessageHandlerSpec
       extends BaseHttpMessageHandlerSpec<WebFluxMessageHandlerSpec,
                                          WebFluxRequestExecutingMessageHandler> {
    // All configuration methods as documented above
}
package org.springframework.integration.webflux.support;

/**
 * BodyExtractor that returns raw ClientHttpResponse without extraction.
 */
public class ClientHttpResponseBodyExtractor
       implements BodyExtractor<ClientHttpResponse, ClientHttpResponse> {
    public ClientHttpResponse extract(ClientHttpResponse response, Context context);
}