@@ -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
4648import jakarta.json.bind.annotation.JsonbCreator;
47- import java.math.BigDecimal;
4849
4950public 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
8584Now 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
9493import java.util.List;
9594
95+ import jakarta.json.JsonArray;
9696import jakarta.ws.rs.GET;
9797import jakarta.ws.rs.Path;
98+ import jakarta.ws.rs.PathParam;
9899import jakarta.ws.rs.Produces;
99100import jakarta.ws.rs.QueryParam;
100101import jakarta.ws.rs.core.MediaType;
101102
102103import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
103104
105+ import io.smallrye.mutiny.Uni;
106+
104107@Path("/v2")
105108@RegisterRestClient
106109public 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
135143import java.util.List;
136144import 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;
138151import jakarta.ws.rs.GET;
139152import jakarta.ws.rs.Path;
140- import jakarta.ws.rs.Produces;
141- import jakarta.ws.rs.core.MediaType;
153+ import jakarta.ws.rs.PathParam;
142154
143155import org.eclipse.microprofile.rest.client.inject.RestClient;
144-
145156import io.smallrye.mutiny.Multi;
157+ import io.smallrye.mutiny.Uni;
146158
147159@Path("/beer")
148160public 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
176186You 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----
183193curl 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