Spring-Reactive aims to bring reactive programming support to Spring based projects and this is expected to be available for the timelines of Spring 5. My intention here is to exercise some of the very basic signatures for REST endpoints with this model.
Before I go ahead let me acknowledge that this entire sample is completely based on the samples which Sébastien Deleuze has put together here - https://github.com/sdeleuze/spring-reactive-playground
I wanted to consider three examples, first a case where existing Java 8 CompletableFuture is returned as a type, second where RxJava's Observable is returned as a type and third with Spring Reactor Core'sFlux type.
The delay_by will make the response to be delayed and throw_exception will make the response to error out. A sane response will be the following:
I will be ignoring the exceptions for this post.
Consider a service which returns a java 8 CompletableFuture as a return type:
The method signature of a Controller which calls this service looks like this now:
When the CompletableFuture completes the framework will ensure that the response is marshalled back appropriately.
The controller invoking such a service can directly return the Observable as a type now and the framework will ensure that once all the items have been emitted the response is marshalled correctly.
Note that since Observable represents a stream of 0 to many items, this time around the response is a json array.
Finally, if the response type is a Flux type, the framework ensures that the response is handled cleanly. The service is along these lines:
and a controller making use of such a service:
I look forward to when the reactive programming model becomes available in the core Spring framework.
The samples presented in this blog post is available at my github repository
Before I go ahead let me acknowledge that this entire sample is completely based on the samples which Sébastien Deleuze has put together here - https://github.com/sdeleuze/spring-reactive-playground
I wanted to consider three examples, first a case where existing Java 8 CompletableFuture is returned as a type, second where RxJava's Observable is returned as a type and third with Spring Reactor Core'sFlux type.
Expected Protocol
The structure of the request and response message handled by each of the three service is along these lines, all of them will take in a request which looks like this:{
"id":1,
"delay_by": 2000,
"payload": "Hello",
"throw_exception": false
}
The delay_by will make the response to be delayed and throw_exception will make the response to error out. A sane response will be the following:
{
"id": "1",
"received": "Hello",
"payload": "Response Message"
}
I will be ignoring the exceptions for this post.
CompletableFuture as a return type
Consider a service which returns a java 8 CompletableFuture as a return type:
public CompletableFuture<MessageAcknowledgement> handleMessage(Message message) {
return CompletableFuture.supplyAsync(() -> {
Util.delay(message.getDelayBy());
return new MessageAcknowledgement(message.getId(), message.getPayload(), "data from CompletableFutureService");
}, futureExecutor);
}
The method signature of a Controller which calls this service looks like this now:
@RestController
public class CompletableFutureController {
private final CompletableFutureService aService;
@Autowired
public CompletableFutureController(CompletableFutureService aService) {
this.aService = aService;
}
@RequestMapping(path = "/handleMessageFuture", method = RequestMethod.POST)
public CompletableFuture<MessageAcknowledgement> handleMessage(@RequestBody Message message) {
return this.aService.handleMessage(message);
}
}
When the CompletableFuture completes the framework will ensure that the response is marshalled back appropriately.
Rx Java Observable as a return type
Consider a service which returns a Rx Java Observable as a return type:public Observable<MessageAcknowledgement> handleMessage(Message message) {
logger.info("About to Acknowledge");
return Observable.just(message)
.delay(message.getDelayBy(), TimeUnit.MILLISECONDS)
.flatMap(msg -> {
if (msg.isThrowException()) {
return Observable.error(new IllegalStateException("Throwing a deliberate exception!"));
}
return Observable.just(new MessageAcknowledgement(message.getId(), message.getPayload(), "From RxJavaService"));
});
}
The controller invoking such a service can directly return the Observable as a type now and the framework will ensure that once all the items have been emitted the response is marshalled correctly.
@RestController
public class RxJavaController {
private final RxJavaService aService;
@Autowired
public RxJavaController(RxJavaService aService) {
this.aService = aService;
}
@RequestMapping(path = "/handleMessageRxJava", method = RequestMethod.POST)
public Observable<MessageAcknowledgement> handleMessage(@RequestBody Message message) {
System.out.println("Got Message..");
return this.aService.handleMessage(message);
}
}
Note that since Observable represents a stream of 0 to many items, this time around the response is a json array.
Spring Reactor Core Flux as a return type
Finally, if the response type is a Flux type, the framework ensures that the response is handled cleanly. The service is along these lines:
public Flux<messageacknowledgement> handleMessage(Message message) {
return Flux.just(message)
.delay(Duration.ofMillis(message.getDelayBy()))
.map(msg -> Tuple.of(msg, msg.isThrowException()))
.flatMap(tup -> {
if (tup.getT2()) {
return Flux.error(new IllegalStateException("Throwing a deliberate Exception!"));
}
Message msg = tup.getT1();
return Flux.just(new MessageAcknowledgement(msg.getId(), msg.getPayload(), "Response from ReactorService"));
});
}
and a controller making use of such a service:
@RestController
public class ReactorController {
private final ReactorService aService;
@Autowired
public ReactorController(ReactorService aService) {
this.aService = aService;
}
@RequestMapping(path = "/handleMessageReactor", method = RequestMethod.POST)
public Flux<MessageAcknowledgement> handleMessage(@RequestBody Message message) {
return this.aService.handleMessage(message);
}
}
Conclusion
This is just a sampling of the kind of return types that the Spring Reactive project supports, the possible return types is way more than this - here is a far more comprehensive example.I look forward to when the reactive programming model becomes available in the core Spring framework.
The samples presented in this blog post is available at my github repository