Reactive REST with Quarkus made easy - Mastertheboss
source link: http://www.mastertheboss.com/soa-cloud/quarkus/reactive-rest-with-quarkus-made-easy/?utm_campaign=reactive-rest-with-quarkus-made-easy
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Reactive REST with Quarkus made easy
Quarkus JAX RS implementation has improved a lot since its first release. Within this tutorial we will show some new features which are available in Quarkus starting from the new reactive REST paradigm.
Quarkus uses SmallRye Mutiny for as main Reactive library. In our first tutorial, we have discussed how to use Mutiny to deliver reactive Hibernate applications: Getting started with Hibernate reactive on Quarkus
We will now dig into Reactive REST Services, showing how you can style REST Services in a modern Quarkus application.
A new Reactive REST framework
The standard model used by REST applications is to use a single Thread for every request. This model, however, is not scalable as you will need one thread for every concurrent request, which places a limit on the achievable concurrency.
To rescue, the reactive execution model enables asynchronous execution and non-blocking IO.
RESTEasy Reactive is the next generation of HTTP framework. It can ensure the best throughput by handling each HTTP request on an IO thread. This model has the following benefits:
- Firstly, smaller response time as there is no thread context switch.
- Next, less memory and cpu usage as it decreases the usage of threads.
- Finally, you are not limited by the number of threads.
Let’s see how to code a Reactive REST application from the grounds up.
Coding a Reactive applications
To start coding our application we can use Quarkus Generator or any other tool (Maven plugin, Quarkus CLI, etc). We need to include the following extension to our project:
This will add in your project, the following dependency:
<dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-resteasy-reactive</artifactId> </dependency>
Next, let’s modify the default Endpoint class as follows:
@Path("/hello") public class ReactiveGreetingResource { @GET @Produces(MediaType.TEXT_PLAIN) public Uni<String> hello() { return Uni.createFrom().item("hello"); } @GET @Produces(MediaType.TEXT_PLAIN) @Path("/greeting/{name}") public Uni<String> greeting(String name) { return Uni.createFrom().item(name) .onItem().transform(n -> String.format("hello %s", name)); } @GET @Produces(MediaType.SERVER_SENT_EVENTS) @RestSseElementType(MediaType.TEXT_PLAIN) @Path("/stream/{count}/{name}") public Multi<String> greetingsAsStream(int count, String name) { return Multi.createFrom().ticks().every(Duration.ofSeconds(1)) .onItem().transform(n -> String.format("hello %s - %d", name, n)) .transform().byTakingFirstItems(count); } }
The main difference compared with classic REST services are Uni and Multi events. As discussed in our first tutorial, Mutiny offers two types that are both event-driven and lazy:
- A
Uni
emits a single event (an item or a failure). A good example is the result of sending a message to a message broker queue. - A
Multi
emits multiple events (n items, 1 failure or 1 completion). A good example is receiving messages from a message broker queue.
Therefore, our Endpoint will produce the following events:
- A
Uni
event which sends the text “hello” as event
- A
Uni
event which publishes a text transformed from the incoming request parameter “name”
- Finally, a
Multi
event which streams a set of greetings events transforming the incoming request parameter “name”
New Parameter Context injection Did you notice our Endpoint does not declare any @PathParam or @RestPath ? With RESTEasy Reactive you don’t need it as long as your parameter has the same name as a path parameter
Handling Server side events
In conclusion, to handle server side events, we will add a minimal AngularJS Module which will poll the REST Endpoint with some Form parameters. We will show just the main code snipped – check the source code for the full example:
<script type="text/javascript"> var app = angular.module("RESTManagement", []); //Controller Part app.controller("RESTController", function ($scope, $http) { $scope.callrest = function () { var url = "hello/stream/" + $scope.form.events + "/" + $scope.form.name; var eventSource = new EventSource(url); eventSource.onmessage = function (event) { var container = document.getElementById("divcontainer"); var paragraph = document.createElement("p"); paragraph.innerHTML = event.data; container.appendChild(paragraph); }; } }); </script>
Running the application
You can build and run the application as usual with:
mvn install quarkus:dev
Next, you can test the following endpoints:
- /hello – returns “hello”
- /greeting/name – returns a greeting for name
- /streaming/name/count – returns a count of SSE with name
Moreover, the home page (index.html) captures the streaming events using AngularJS:
Adding per-class Exception Mapper
In the JAX-RS specification all exception mapping is done in a global manner. However, when using RESTEasy Reactive you can handle exceptions with a specific JAX-RS Resource Class through the annotation @ServerExceptionMapping:
@GET @Produces(MediaType.TEXT_PLAIN) @Path("/greeting/{name}") public Uni<String> greeting(String name) { if (name == null || name.size().trim() == 0) { throw new IllegalArgumentException(); } return Uni.createFrom().item(name) .onItem().transform(n -> String.format("hello %s", name)); } @ServerExceptionMapper(IllegalArgumentException.class) public Response handleIllegal() { return Response.status(409).build(); }
In the above example, the Exception mapper will be called only for exceptions thrown in the same class. If you want to intercept exceptions globally, simply define them outside of the Endpoint. For example:
class ExceptionMappers { @ServerExceptionMapper public RestResponse<String> mapException(IllegalArgumentException exc) { return RestResponse.status(Response.Status.CONFLICT, "Illegal argument!"); } }
Source code for this tutorial: https://github.com/fmarchioni/mastertheboss/tree/master/quarkus/jaxrs-reactive
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK