Skip to content

Commit b73dfac

Browse files
committed
Update with reactive quarkus
1 parent 0b67a40 commit b73dfac

5 files changed

Lines changed: 125 additions & 34 deletions

File tree

apps/reactive-quarkus

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Subproject commit 00f4afd2cb9a37af1920a51a72a1408d59a00c81
552 KB
Loading
572 KB
Loading

documentation/modules/ROOT/nav.adoc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
** xref:security.adoc[Security with JWT RBAC]
1818
// ** xref:security-oidc.adoc[Security using OpenID Connect]
1919
20-
// * Reactive
21-
// ** xref:reactive.adoc[Reactive with Mutiny]
22-
// ** xref:reactive-messaging.adoc[Streaming reactive messages]
23-
// ** xref:kafka-and-streams.adoc[Apache Kafka with Reactive Streams]
20+
* Reactive
21+
** xref:reactive.adoc[Reactive with Mutiny]
22+
** xref:reactive-messaging.adoc[Streaming reactive messages]
23+
** xref:kafka-and-streams.adoc[Apache Kafka with Reactive Streams]

documentation/modules/ROOT/pages/reactive.adoc

Lines changed: 120 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ Then we're going to filter all the beers with an ABV greater than 15.0 and retur
99

1010
== Add the Mutiny extension
1111

12-
Just open a new terminal window, and make sure you’re at the root of your `{project-name}` project, then run:
12+
Create a new Quarkus project, for example using https://code.quarkus.io/ website.
13+
14+
Then open a new terminal window, and make sure you’re at the root of your `{project-name}` project, then run:
1315

1416
[tabs]
1517
====
@@ -19,7 +21,7 @@ Maven::
1921
[.console-input]
2022
[source,bash,subs="+macros,+attributes"]
2123
----
22-
./mvnw quarkus:add-extension -Dextension=quarkus-mutiny
24+
./mvnw quarkus:add-extension -Dextension=quarkus-mutiny,quarkus-rest-client-reactive-jsonb,quarkus-resteasy-reactive-jsonb
2325
----
2426
2527
--
@@ -29,29 +31,26 @@ Quarkus CLI::
2931
[.console-input]
3032
[source,bash,subs="+macros,+attributes"]
3133
----
32-
quarkus extension add quarkus-mutiny
34+
quarkus extension add quarkus-mutiny,quarkus-rest-client-reactive-jsonb,quarkus-resteasy-reactive-jsonb
3335
----
3436
--
3537
====
3638

3739
== Create Beer POJO
3840

39-
Create a new `Beer` Java class in `src/main/java` in the `com.redhat.developers` package with the following contents:
41+
Create a new `Beer` Java class in `src/main/java` in the `org.acme` package with the following contents:
4042

4143
[.console-input]
4244
[source,java]
4345
----
44-
package com.redhat.developers;
46+
package org.acme;
4547
4648
import jakarta.json.bind.annotation.JsonbCreator;
47-
import java.math.BigDecimal;
4849
4950
public class Beer {
5051
5152
private String name;
52-
5353
private String tagline;
54-
5554
private double abv;
5655
5756
private Beer(String name, String tagline, double abv) {
@@ -84,32 +83,35 @@ public class Beer {
8483

8584
Now we're going to implement a Java interface that mimics the remote REST endpoint.
8685

87-
Create a new `BeerService` Java interface in `src/main/java` in the `com.redhat.developers` package with the following contents:
86+
Create a new `BeerService` Java interface in `src/main/java` in the `org.acme` package with the following contents:
8887

8988
[.console-input]
9089
[source,java]
9190
----
92-
package com.redhat.developers;
91+
package org.acme;
9392
9493
import java.util.List;
9594
95+
import jakarta.json.JsonArray;
9696
import jakarta.ws.rs.GET;
9797
import jakarta.ws.rs.Path;
98+
import jakarta.ws.rs.PathParam;
9899
import jakarta.ws.rs.Produces;
99100
import jakarta.ws.rs.QueryParam;
100101
import jakarta.ws.rs.core.MediaType;
101102
102103
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
103104
105+
import io.smallrye.mutiny.Uni;
106+
104107
@Path("/v2")
105108
@RegisterRestClient
106109
public interface BeerService {
107-
110+
108111
@GET
109112
@Path("/beers")
110113
@Produces(MediaType.APPLICATION_JSON)
111-
List<Beer> getBeers(@QueryParam("page") int page);
112-
114+
Uni<List<Beer>> getBeers(@QueryParam("page") int page);
113115
}
114116
----
115117

@@ -120,49 +122,57 @@ Add the following properties to your `application.properties` in `src/main/resou
120122
[.console-input]
121123
[source,properties]
122124
----
123-
com.redhat.developers.BeerService/mp-rest/url=https://api.punkapi.com
125+
org.acme.BeerService/mp-rest/url=https://api.punkapi.com
124126
----
125127

126-
== Create BeerResource
128+
== Pagination + Filtering
129+
130+
We want to query all the beers page by page and filter by its _abv_ value.
127131

128-
Create a new `BeerResource` Java class in `src/main/java` in the `com.redhat.developers` package with the following contents:
132+
image::pagination.png[]
133+
134+
=== Create BeerResource
135+
136+
Create a new `BeerResource` Java class in `src/main/java` in the `org.acme` package with the following contents:
129137

130138
[.console-input]
131139
[source,java]
132140
----
133-
package com.redhat.developers;
141+
package org.acme;
134142
135143
import java.util.List;
136144
import java.util.concurrent.atomic.AtomicInteger;
137145
146+
import jakarta.json.Json;
147+
import jakarta.json.JsonArray;
148+
import jakarta.json.JsonMergePatch;
149+
import jakarta.json.JsonObject;
150+
import jakarta.json.JsonValue;
138151
import jakarta.ws.rs.GET;
139152
import jakarta.ws.rs.Path;
140-
import jakarta.ws.rs.Produces;
141-
import jakarta.ws.rs.core.MediaType;
153+
import jakarta.ws.rs.PathParam;
142154
143155
import org.eclipse.microprofile.rest.client.inject.RestClient;
144-
145156
import io.smallrye.mutiny.Multi;
157+
import io.smallrye.mutiny.Uni;
146158
147159
@Path("/beer")
148160
public class BeerResource {
149-
161+
150162
@RestClient
151163
BeerService beerService;
152164
153165
@GET
154-
@Produces(MediaType.APPLICATION_JSON)
155166
public Multi<Beer> beers() {
156-
return Multi.createBy().repeating() <1>
157-
.supplier( <2>
167+
return Multi.createBy().repeating() // <1>
168+
.uni(
158169
() -> new AtomicInteger(1),
159-
i -> beerService.getBeers(i.getAndIncrement())
170+
i -> beerService.getBeers(i.getAndIncrement()) // <2>
160171
)
161-
.until(List::isEmpty) <3>
162-
.onItem().<Beer>disjoint() <4>
163-
.select().where(b -> b.getAbv() > 15.0); <6>
172+
.until(List::isEmpty) // <3>
173+
.onItem().<Beer>disjoint() // <4>
174+
.select().where(b -> b.getAbv() > 15.0); // <5>
164175
}
165-
166176
}
167177
----
168178
<1> Creates a `Multi`.
@@ -171,7 +181,7 @@ public class BeerResource {
171181
<4> We dismember all the returned lists and create a sequence of beers.
172182
<5> And then we filter the `Multi` with beers with `ABV > 15.0`.
173183

174-
== Invoke the endpoint
184+
=== Invoke the endpoint
175185

176186
You can check your new implementation by pointing your browser to http://localhost:8080/beer[window=_blank]
177187

@@ -182,6 +192,7 @@ You can also run the following command:
182192
----
183193
curl localhost:8080/beer
184194
----
195+
185196
[.console-output]
186197
[source,json]
187198
----
@@ -248,3 +259,82 @@ curl localhost:8080/beer
248259
}
249260
]
250261
----
262+
263+
== Parallel Calls
264+
265+
Suppose that now, you want to query two beers by its id, (so execute two requests against the remote API), and then compare its _abv_ values.
266+
267+
image::parallel.png[]
268+
269+
=== Modify BeerService
270+
271+
Open `BeerService` interface and add the following method to get a beer:
272+
273+
[.console-input]
274+
[source,java]
275+
----
276+
@GET
277+
@Path("/beers/{id}")
278+
@Produces(MediaType.APPLICATION_JSON)
279+
Uni<JsonArray> getBeer(@PathParam("id") int id);
280+
----
281+
282+
=== Modify BeerResource
283+
284+
Open `BeerResource` class and add the following methods to do in parallel the both calls.
285+
286+
[.console-input]
287+
[source,java]
288+
----
289+
@GET
290+
@Path("/{beerA}/{beerB}")
291+
public Uni<JsonValue> compare(@PathParam("beerA") int beerA, @PathParam("beerB") int beerB) {
292+
Uni<JsonArray> beer1 = beerService.getBeer(beerA); // <1>
293+
Uni<JsonArray> beer2 = beerService.getBeer(beerB); // <2>
294+
295+
return Uni.combine()
296+
.all()
297+
.unis(beer1, beer2) // <3>
298+
.with((b1, b2) -> this.compare(b1, b2)); // <4>
299+
}
300+
301+
private JsonValue compare(JsonArray beerA, JsonArray beerB) {
302+
JsonObject source = beerA.get(0).asJsonObject();
303+
JsonObject target = beerB.get(0).asJsonObject();
304+
305+
String beerAName = source.getString("name");
306+
String beerBName = target.getString("name");
307+
308+
double beerAAbv = source.getJsonNumber("abv").doubleValue();
309+
double beerBAbv = target.getJsonNumber("abv").doubleValue();
310+
311+
return Json.createObjectBuilder()
312+
.add("source-name", beerAName)
313+
.add("target-name", beerBName)
314+
.add("source-abv", beerAAbv)
315+
.add("target-abv", beerBAbv)
316+
.build();
317+
}
318+
----
319+
<1> Executes request for first beer
320+
<2> Executes request for second beer
321+
<3> Waits until both requests returns a response
322+
<4> Compare both beers and returns an object with the result
323+
324+
=== Invoke the endpoint
325+
326+
You can check your new implementation by pointing your browser to http://localhost:8080/beer/1/2[window=_blank]
327+
328+
You can also run the following command:
329+
330+
[.console-input]
331+
[source,bash]
332+
----
333+
curl localhost:8080/beer/1/2
334+
----
335+
336+
[.console-output]
337+
[source,json]
338+
----
339+
{"source-name":"Buzz","target-name":"Trashy Blonde","source-abv":4.5,"target-abv":4.1}
340+
----

0 commit comments

Comments
 (0)