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

WebFlux.outboundGateway has no way of producing Flux<Anything> #2300

Closed
asarkar opened this Issue Dec 7, 2017 · 7 comments

Comments

Projects
None yet
3 participants
@asarkar

asarkar commented Dec 7, 2017

In WebFluxRequestExecutingMessageHandler, I see the following:

if (expectedResponseType instanceof ParameterizedTypeReference<?>) {
  bodyMono = response.body(BodyExtractors.toMono((ParameterizedTypeReference<?>) expectedResponseType));
}
else if (expectedResponseType != null) {
	bodyMono = response.body(BodyExtractors.toMono((Class<?>) expectedResponseType));
}

What I'm expecting as response is Flux<DataBuffer> that I can do some processing on before sending to an output channel. However, the above code always forces the body to be converted to Mono.

The documentation for webflux support merely regurgitates what's in the code.

The WebClient exchange() operation returns a Mono which is mapped to the AbstractIntegrationMessageBuilder reactive support (using Mono.map()) as the output from the WebFluxRequestExecutingMessageHandler. Together with the ReactiveChannel as an outputChannel, the Mono evaluation is deferred until a downstream subscription is made. Otherwise, it is treated as an async mode and the Mono response is adapted to an SettableListenableFuture for an asynchronous reply from the WebFluxRequestExecutingMessageHandler.

It'd be nice to also see some examples for how to get a Flux<UserDataType>, Flux<DataBuffer>, Mono<ClientResponse> etc. As with RestTemplate, where I've the option to get the ResponseEntity if I want to do the processing myself, I should also be able to get Mono<ClientResponse> should I so choose.

artembilan added a commit to artembilan/spring-integration that referenced this issue Dec 14, 2017

spring-projectsGH-2300: Add Flux support in WebFluxRequestExecMH
Fixes: spring-projects#2300

To allow to consume a streaming HTTP response downstream expose
`replyToFlux` option on the `WebFluxRequestExecutingMessageHandler`.
This way the body of the HTTP response can be converted now to the
`Flux` for subsequent output message.
The option is `false` by default; can be changed to `true` in the `5.1`
@artembilan

This comment has been minimized.

Show comment
Hide comment
@artembilan

artembilan Dec 14, 2017

Member

Same here. The PR on the matter #2304

Member

artembilan commented Dec 14, 2017

Same here. The PR on the matter #2304

@asarkar

This comment has been minimized.

Show comment
Hide comment
@asarkar

asarkar Dec 14, 2017

This looks good but how do I get a Mono<ClientResponse>? Seems like it always calls BodyExtractor. Perhaps you can check that the parameterized type isn't Mono<ClientResponse>, and if it is, simply hand the response back, otherwise, extract the body.

asarkar commented Dec 14, 2017

This looks good but how do I get a Mono<ClientResponse>? Seems like it always calls BodyExtractor. Perhaps you can check that the parameterized type isn't Mono<ClientResponse>, and if it is, simply hand the response back, otherwise, extract the body.

@artembilan

This comment has been minimized.

Show comment
Hide comment
@artembilan

artembilan Dec 14, 2017

Member

Correct. That is not Spring Integration and Messaging architecture responsibility to expose such a low level resource. If you really need the access to it and do low-level logic around, consider to use WebClient directly in some POJO for the @ServiceActivator.

Anyway in this case we provide the body converted to the payload via provided HttpMessageReaders and HTTP headers are copied into the MessageHeaders according HeaderMapper. So, technically you have everything in the Message what you could get from the ClientResponse directly.

Member

artembilan commented Dec 14, 2017

Correct. That is not Spring Integration and Messaging architecture responsibility to expose such a low level resource. If you really need the access to it and do low-level logic around, consider to use WebClient directly in some POJO for the @ServiceActivator.

Anyway in this case we provide the body converted to the payload via provided HttpMessageReaders and HTTP headers are copied into the MessageHeaders according HeaderMapper. So, technically you have everything in the Message what you could get from the ClientResponse directly.

@asarkar

This comment has been minimized.

Show comment
Hide comment
@asarkar

asarkar Dec 14, 2017

you have everything in the Message what you could get from the ClientResponse directly.

That's not true. One example where that doesn't work is when the response is compressed. Your PR would produce a Flux<DataBuffer> which would be useless until the caller can reconstruct the InputStream and decompress it. Other examples might include not parsing the body at all if they see a particular header or something like that.

Point is, I don't understand why you'd force someone to write more code which can be supported by framework in the first place, and with little effort? Having a Message<Mono<ClientResponse>> is not breaking the messaging paradigm. The caller is in the best position to decide what should be in the message, not the framework author.

asarkar commented Dec 14, 2017

you have everything in the Message what you could get from the ClientResponse directly.

That's not true. One example where that doesn't work is when the response is compressed. Your PR would produce a Flux<DataBuffer> which would be useless until the caller can reconstruct the InputStream and decompress it. Other examples might include not parsing the body at all if they see a particular header or something like that.

Point is, I don't understand why you'd force someone to write more code which can be supported by framework in the first place, and with little effort? Having a Message<Mono<ClientResponse>> is not breaking the messaging paradigm. The caller is in the best position to decide what should be in the message, not the framework author.

@artembilan

This comment has been minimized.

Show comment
Hide comment
@artembilan

artembilan Dec 14, 2017

Member

Yeah... That existing status quo with all other channel adapters...

@garyrussell , any thoughts since we always convert low-level response to our "convenient" representation?

I may suggest to let to inject something like BodyExtractor which simple can be like:

(inputMessage, context) -> inputMessage

Where that inputMessage is exactly ClientResponse and you will get the message with it downstream.

Member

artembilan commented Dec 14, 2017

Yeah... That existing status quo with all other channel adapters...

@garyrussell , any thoughts since we always convert low-level response to our "convenient" representation?

I may suggest to let to inject something like BodyExtractor which simple can be like:

(inputMessage, context) -> inputMessage

Where that inputMessage is exactly ClientResponse and you will get the message with it downstream.

@garyrussell

This comment has been minimized.

Show comment
Hide comment
@garyrussell

garyrussell Dec 14, 2017

Member

Sounds like a reasonable compromise. Maybe provide a canned NoOpBodyExtractor or at least document the lambda.

Member

garyrussell commented Dec 14, 2017

Sounds like a reasonable compromise. Maybe provide a canned NoOpBodyExtractor or at least document the lambda.

@artembilan

This comment has been minimized.

Show comment
Hide comment
@artembilan

artembilan Dec 15, 2017

Member

@asarkar ,
let us know WDYT about previous discussion?
And let's move it to the PR already! That is much easier to comment on the code lines for the appropriate context.

For your compressed response use-case I would suggest to take a look into the HttpMessageReader abstraction which can be injected into the WebClient via its:

.exchangeStrategies(ExchangeStrategies.builder()
						.codecs(clientCodecConfigurer -> 
                                                                    clientCodecConfigurer.customCodecs()
                                                                                   .reader(...))
						.build())
Member

artembilan commented Dec 15, 2017

@asarkar ,
let us know WDYT about previous discussion?
And let's move it to the PR already! That is much easier to comment on the code lines for the appropriate context.

For your compressed response use-case I would suggest to take a look into the HttpMessageReader abstraction which can be injected into the WebClient via its:

.exchangeStrategies(ExchangeStrategies.builder()
						.codecs(clientCodecConfigurer -> 
                                                                    clientCodecConfigurer.customCodecs()
                                                                                   .reader(...))
						.build())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment