Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Spring-Reactive Example REST Application

DZone's Guide to

Spring-Reactive Example REST Application

Spring Reactive is a sandbox for experimenting on the reactive support intended to be part of Spring Framework 5. This post provides an example REST application built with this library.

· Integration Zone
Free Resource

Learn how API management supports better integration in Achieving Enterprise Agility with Microservices and API Management, brought to you in partnership with 3scale

Spring-Reactive aims to bring reactive programming support to Spring-based projects and 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.

Expected Protocol

The structure of the request and response message handled by each of the three services 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 delayed and throw_exception will make the response error out. A sane response would 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 marshaled 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 marshaled 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

    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

Unleash the power of your APIs with future-proof API management - Create your account and start your free trial today, brought to you in partnership with 3scale.

Topics:
flux ,spring ,rest ,reactive

Published at DZone with permission of Biju Kunjummen, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}