Skip to content

GH 3936 : Request attribute for webclient in webflux integration has been added #3950

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,12 @@ public void setPublisherElementTypeExpression(Expression publisherElementTypeExp
this.publisherElementTypeExpression = publisherElementTypeExpression;
}

/**
* Configure expression to evaluate request attribute which will be added to webclient request attribute.
* @param attributeVariablesExpression the expression to evaluate request attribute.
* @since 6.0
* @see WebFluxRequestExecutingMessageHandler#evaluateAttributeVariables(Message)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are pointing here to private method which is out of end-user interest.
I'd say @see WebClient.RequestBodySpec#attributes

*/
public void setAttributeVariablesExpression(Expression attributeVariablesExpression) {
Assert.notNull(attributeVariablesExpression, "'attributeVariablesExpression' must not be null");
this.attributeVariablesExpression = attributeVariablesExpression;
Expand Down Expand Up @@ -249,9 +255,11 @@ private WebClient.RequestBodySpec createRequestBodySpec(Object uri, HttpMethod h

requestSpec = requestSpec.headers(headers -> headers.putAll(httpRequest.getHeaders()));

if(attributeVariablesExpression != null) {
if (this.attributeVariablesExpression != null) {
Map<String, Object> attributeMap = evaluateAttributeVariables(requestMessage);
requestSpec = requestSpec.attributes(map -> map.putAll(attributeMap));
if (attributeMap != null && !attributeMap.isEmpty()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

!CollectionUtils.isEmpty(attributeMap)

requestSpec = requestSpec.attributes(map -> map.putAll(attributeMap));
}
}

BodyInserter<?, ? super ClientHttpRequest> inserter = buildBodyInserterForRequest(requestMessage, httpRequest);
Expand Down Expand Up @@ -393,7 +401,8 @@ private Object createReplyFromResponse(Mono<ResponseEntity<Flux<Object>>> respon
.map(this::getReply);
}

private Map<String,Object> evaluateAttributeVariables(Message<?> requestMessage){
@SuppressWarnings("unchecked")
private Map<String, Object> evaluateAttributeVariables(Message<?> requestMessage) {
return this.attributeVariablesExpression.getValue(this.evaluationContext, requestMessage, Map.class);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -401,16 +401,16 @@ void testFluxReplyWithRequestAttribute() {
.then(Mono.defer(response::setComplete));
});

class AttributeFilter implements ExchangeFilterFunction {
class AttributeFilter implements ExchangeFilterFunction {

Optional<Object> attributeValueName;

@Override
public Mono<ClientResponse> filter(ClientRequest request, ExchangeFunction next) {
this.attributeValueName = request.attribute("name");
return next.exchange(request);
}
}
@Override
public Mono<ClientResponse> filter(ClientRequest request, ExchangeFunction next) {
this.attributeValueName = request.attribute("name");
return next.exchange(request);
}
}

AttributeFilter attributeFilter = new AttributeFilter();
WebClient webClient = WebClient.builder()
Expand All @@ -437,7 +437,7 @@ public Mono<ClientResponse> filter(ClientRequest request, ExchangeFunction next)

assertThat(attributeFilter.attributeValueName).isPresent();

Map<String,String> attributeValueNameMap = (Map<String, String>) attributeFilter.attributeValueName.get();
Map<String, String> attributeValueNameMap = (Map<String, String>) attributeFilter.attributeValueName.get();

assertThat(attributeValueNameMap.get("first")).isEqualTo("Nikola");

Expand Down
3 changes: 2 additions & 1 deletion src/reference/asciidoc/webflux.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -323,4 +323,5 @@ See <<./http.adoc#http-header-mapping,HTTP Header Mappings>> for more possible o
[[webflux-request-attribute]]
=== WebFlux Request Attribute
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Attributes


Starting with Version 6, Webflux outbound request can have request attribute which can be specified in `attribute-variables-expression` attribute. This attribute will take an `expression` that should be evaluated in `Map`.
Starting with version 6.0, Webflux outbound request `WebFluxRequestExecutingMessageHandler` can have request attribute which can be specified in `setAttributeVariablesExpression()`.
This will take an `expression` that should be evaluated in `Map`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still would like to see a general sentence for reasoning behind these attributes.
Doesn't look like this is a common feature since we haven't bumped to its missing support for since version 5.0.
Probably the security would be a great sample to carry on some info from message to the request where downstream filter would expect an attribute to be able to authorize a principal or so.

My point is that you need to convince me somehow in using this new feature from the doc.
No one is going to look into those tests in the project.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how about this?

Starting with version 6.0, Webflux outbound request WebFluxRequestExecutingMessageHandler can have request attributes which can be specified in setAttributeVariablesExpression().
This will take an expression that should be evaluated in Map.
This will be helpful if an information in form of key-value object needs be passed from Message to request and downstream filter will get access to this attribute for further processing.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good!
👍

5 changes: 3 additions & 2 deletions src/reference/asciidoc/whats-new.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -188,9 +188,10 @@ The `ChannelSecurityInterceptor` and its annotation `@SecuredChannel` and XML `<
See <<./security.adoc#security,Security Support>> for more information.

[[x6.0-webflux]]

=== Webflux request attribute support
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blank line here between name and section body.

Webclient Request attribute support has been added for outbound request.See <<./webflux.adoc#webflux-request-attribute,WebFlux Request Attribute>> for more information.

Webclient Request attribute support has been added for outbound request.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

attributes and probably better to mention a WebFluxRequestExecutingMessageHandler.
That "outbound request" is too vague from Spring Integration context.

See <<./webflux.adoc#webflux-request-attribute,WebFlux Request Attribute>> for more information.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Attributes