Skip to content

Commit

Permalink
feat: component client samples update (#1706)
Browse files Browse the repository at this point in the history
* feat: component client samples update

* reverting test changes

* fixing sample code after rebase
  • Loading branch information
aludwiko authored Jun 27, 2023
1 parent 5e2dd9d commit 8c7b5d2
Show file tree
Hide file tree
Showing 16 changed files with 133 additions and 117 deletions.
8 changes: 4 additions & 4 deletions docs/src/modules/java/pages/actions.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,14 @@ request and only conditionally forward the request to the entity if the verifica
----
include::example$java-spring-valueentity-shopping-cart/src/main/java/com/example/api/ShoppingCartController.java[tag=forward]
----
<1> `KalixClient` is injected on the constructor. It will be used to build calls to the underlining Entity.
<1> `ComponentClient` is injected on the constructor. It will be used to build calls to the underlining Entity.
<2> Expose the command handler as a `POST` endpoint at specified path.
<3> Check if the added item is carrots.
<4> If it is "carrots" immediately return an error, disallowing adding the item.
<5> For allowed requests, use `kalixClient` to get a deferred call to the entity.
<5> For allowed requests, use `componentClient` to get a deferred call to the entity.
<6> The `deferredCall` is then used with `effects().forward()` to forward the request to the entity.

NOTE: You might be wondering what the `kalixClient` is about. For now, think of it as a lightweight HTTP client allowing you to reach out to other Kalix services. All details can be found at xref:call-another-service.adoc[] chapter.
NOTE: NOTE: You might be wondering what the `componentClient` is about. For now, think of it as a lightweight, type safe, HTTP client allowing you to reach out to other Kalix services. All details can be found at xref:call-another-service.adoc[] chapter.

=== Transform Request and Response to Another Component

Expand All @@ -98,7 +98,7 @@ This example implements an `initializeCart` command for the controller Action wh
include::example$java-spring-valueentity-shopping-cart/src/main/java/com/example/api/ShoppingCartController.java[tag=initialize]
----
<1> Generate a new UUID.
<2> Use the `kalixClient` to create a call to endpoint `create` on the shopping cart - note the use of the full path, empty body and the expected reply type `ShoppingCartDTO`.
<2> Use the `componentClient` to create a call to endpoint `create` on the shopping cart.
<3> `execute()` on the deferred call immediately triggers a call and returns a `CompletionStage` for the response.
<4> Once the call succeeds or fails the `CompletionStage` is completed or failed, we can transform the result from `CompletionStage<Empty>`.
to `CompletionStage<Effect<String>>` using `handle`.
Expand Down
2 changes: 1 addition & 1 deletion docs/src/modules/java/pages/timers.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ include::example$java-spring-reliable-timers/src/main/java/com/example/actions/O
<3> Order id is used to generate a unique name for the timer.
<4> Set the delay you want for the timer to trigger.
<5> Scheduled call to `OrderAction.expire` method. We will cover it in a while.
<6> Pass on the request for the Order entity specifying the `orderId` using the `KalixClient`.
<6> Pass on the request for the Order entity using the `ComponentClient`.
<7> Finally, you build an `asyncReply` by composing the `timerRegistration` CompletionStage with a call to execute the request and place the order.

In a nutshell, you first requested Kalix to register a timer. When it completes, you know that the timer is persisted and will run at the specified time. You then proceed by placing the order.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,35 +1,38 @@
package com.example.actions;

import com.example.Counter;
import kalix.javasdk.action.Action;
import kalix.javasdk.annotations.Subscribe;
import kalix.spring.KalixClient;
import kalix.javasdk.client.ComponentClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Subscribe.Topic(value = "counter-commands", ignoreUnknown = true)
public class CounterCommandFromTopicAction extends Action {

public record IncreaseCounter(String counterId, int value) { }
public record MultiplyCounter(String counterId, int value) { }
public record IncreaseCounter(String counterId, int value) {
}

public record MultiplyCounter(String counterId, int value) {
}

private KalixClient kalixClient;
private ComponentClient componentClient;

public CounterCommandFromTopicAction(KalixClient kalixClient) {
this.kalixClient = kalixClient;
public CounterCommandFromTopicAction(ComponentClient componentClient) {
this.componentClient = componentClient;
}

private Logger logger = LoggerFactory.getLogger(CounterCommandFromTopicAction.class);

public Effect<String> onValueIncreased(IncreaseCounter increase) {
logger.info("Received increase command: " + increase.toString());
var deferredCall = kalixClient.post("/counter/"+ increase.counterId + "/increase/" + increase.value, String.class);
var deferredCall = componentClient.forEventSourcedEntity(increase.counterId).call(Counter::increase).params(increase.value);
return effects().forward(deferredCall);
}

public Effect<String> onValueDecreased(MultiplyCounter increase) {
public Effect<String> onValueMultiplied(MultiplyCounter increase) {
logger.info("Received increase command: " + increase.toString());
var deferredCall = kalixClient.post("/counter/"+ increase.counterId + "/multiply/" + increase.value, String.class);
var deferredCall = componentClient.forEventSourcedEntity(increase.counterId).call(Counter::multiply).params(increase.value);
return effects().forward(deferredCall);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,16 @@

import com.example.Main;
import kalix.spring.testkit.KalixIntegrationTestKitSupport;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.TestPropertySource;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.client.WebClientResponseException;
import reactor.core.publisher.Mono;

import java.time.Duration;
import java.time.temporal.ChronoUnit;

import static java.time.temporal.ChronoUnit.SECONDS;

Expand All @@ -29,9 +26,9 @@ public class FibonacciActionIntegrationTest extends KalixIntegrationTestKitSuppo
public void calculateNextNumber() {

Mono<Number> response =
webClient.get()
.uri("/fibonacci/5/next")
.retrieve().bodyToMono(Number.class);
webClient.get()
.uri("/fibonacci/5/next")
.retrieve().bodyToMono(Number.class);

long next = response.block(Duration.of(5, SECONDS)).value();
Assertions.assertEquals(8, next);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ private long nextFib(long num) { // <2>
}

@GetMapping("/{number}/next")
public Effect<Number> nextNumber(@PathVariable Long number) { // <3>
public Effect<Number> getNumber(@PathVariable Long number) { // <3>
return nextNumber(new Number(number));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import io.grpc.Status;
import kalix.javasdk.action.Action;
import kalix.javasdk.action.ActionCreationContext;
import kalix.spring.KalixClient;
import kalix.javasdk.client.ComponentClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;
Expand All @@ -13,14 +13,14 @@ public class LimitedFibonacciAction extends Action {

private static final Logger logger = LoggerFactory.getLogger(LimitedFibonacciAction.class);

private KalixClient kalixClient;
private ComponentClient componentClient;

private ActionCreationContext ctx;


public LimitedFibonacciAction(ActionCreationContext ctx, KalixClient kalixClient) {
public LimitedFibonacciAction(ActionCreationContext ctx, ComponentClient componentClient) {
this.ctx = ctx;
this.kalixClient = kalixClient;
this.componentClient = componentClient;
}

@GetMapping("/{number}/next")
Expand All @@ -29,7 +29,7 @@ public Effect<Number> nextNumber(@PathVariable Long number) {
return effects().error("Only numbers between 0 and 10k are allowed", Status.Code.INVALID_ARGUMENT);
} else {
logger.info("Executing GET call to real /fibonacci = " + number);
var serviceCall = kalixClient.get("/fibonacci/"+number+"/next", Number.class);
var serviceCall = componentClient.forAction().call(FibonacciAction::getNumber).params(number);

return effects().forward(serviceCall);
}
Expand All @@ -41,7 +41,7 @@ public Effect<Number> nextNumber(@RequestBody Number number) {
return effects().error("Only numbers between 0 and 10k are allowed", Status.Code.INVALID_ARGUMENT);
} else {
logger.info("Executing POST call to real /fibonacci = " + number.value());
var serviceCall = kalixClient.post("/fibonacci/next", number, Number.class);
var serviceCall = componentClient.forAction().call(FibonacciAction::nextNumber).params(number);

return effects().forward(serviceCall);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@ public class FibonacciActionTest {
@Test
public void testNextFib() {
ActionTestkit<FibonacciAction> testkit = ActionTestkit.of(FibonacciAction::new); // <1>
ActionResult<Number> result = testkit.call(a -> a.nextNumber(3L)); // <2>
ActionResult<Number> result = testkit.call(a -> a.getNumber(3L)); // <2>
assertTrue(result.isReply());
assertEquals(5L, result.getReply().value());
}

@Test
public void testNextFibError() {
ActionTestkit<FibonacciAction> testkit = ActionTestkit.of(FibonacciAction::new); // <1>
ActionResult<Number> result = testkit.call(a -> a.nextNumber(4L)); // <2>
ActionResult<Number> result = testkit.call(a -> a.getNumber(4L)); // <2>
assertTrue(result.isError());
assertTrue(result.getError().startsWith("Input number is not a Fibonacci number"));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<logger name="io.grpc.netty" level="INFO"/>
<logger name="org.testcontainers" level="INFO"/>

<root level="DEBUG">
<root level="INFO">
<appender-ref ref="STDOUT"/>
</root>
</configuration>
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package com.example.actions;

import akka.Done;
import com.example.domain.OrderEntity;
import com.example.domain.OrderRequest;
import com.example.domain.Order;
import kalix.javasdk.DeferredCallResponseException;
import kalix.javasdk.StatusCode.ErrorCode;
import kalix.javasdk.action.Action;
import kalix.javasdk.action.ActionCreationContext;
import kalix.spring.KalixClient;
import kalix.javasdk.client.ComponentClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;
Expand All @@ -24,14 +25,14 @@ public class OrderAction extends Action {

private Logger logger = LoggerFactory.getLogger(getClass());

private KalixClient kalixClient;
private ComponentClient componentClient;

private ActionCreationContext ctx;


public OrderAction(ActionCreationContext creationContext, KalixClient kalixClient) {
public OrderAction(ActionCreationContext creationContext, ComponentClient componentClient) {
this.ctx = creationContext;
this.kalixClient = kalixClient;
this.componentClient = componentClient;
}

// tag::place-order[]
Expand All @@ -46,9 +47,9 @@ public Effect<Order> placeOrder(@RequestBody OrderRequest orderRequest) {

CompletionStage<Done> timerRegistration = // <2>
timers().startSingleTimer(
timerName(orderId), // <3>
Duration.ofSeconds(10), // <4>
kalixClient.post("/orders/expire/"+orderId, "", String.class) // <5>
timerName(orderId), // <3>
Duration.ofSeconds(10), // <4>
componentClient.forAction().call(OrderAction::expire).params(orderId) // <5>
);

// end::place-order[]
Expand All @@ -59,7 +60,7 @@ public Effect<Order> placeOrder(@RequestBody OrderRequest orderRequest) {
orderId);
// tag::place-order[]

var request = kalixClient.put("/order/"+orderId+"/place", orderRequest, Order.class); // <6>
var request = componentClient.forValueEntity(orderId).call(OrderEntity::placeOrder).params(orderRequest); // <6>
return effects().asyncReply( // <7>
timerRegistration
.thenCompose(done -> request.execute())
Expand All @@ -74,7 +75,7 @@ public Effect<Order> placeOrder(@RequestBody OrderRequest orderRequest) {
@PostMapping("/expire/{orderId}")
public Effect<String> expire(@PathVariable String orderId) {
logger.info("Expiring order '{}'", orderId);
var cancelRequest = kalixClient.post("/order/"+orderId+"/cancel", "", String.class);
var cancelRequest = componentClient.forValueEntity(orderId).call(OrderEntity::cancel);

CompletionStage<String> reply =
cancelRequest
Expand Down Expand Up @@ -103,8 +104,8 @@ public Effect<String> confirm(@PathVariable String orderId) {
logger.info("Confirming order '{}'", orderId);

CompletionStage<String> reply =
kalixClient.post("/order/"+orderId+"/confirm", "", String.class) // <1>
.execute()
componentClient.forValueEntity(orderId).call(OrderEntity::confirm) // <1>
.execute()
.thenCompose(req -> timers().cancel(timerName(orderId))) // <2>
.thenApply(done -> "Ok");

Expand All @@ -116,7 +117,7 @@ public Effect<String> cancel(@PathVariable String orderId) {
logger.info("Cancelling order '{}'", orderId);

CompletionStage<String> reply =
kalixClient.post("/order/"+orderId+"/cancel", "", String.class)
componentClient.forValueEntity(orderId).call(OrderEntity::cancel)
.execute()
.thenCompose(req -> timers().cancel(timerName(orderId)))
.thenApply(done -> "Ok");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,40 +29,42 @@ public Order emptyState() {
}

@PutMapping("/place")
public Effect<Order> placeOrder(@PathVariable String id,
@RequestBody OrderRequest orderRequest) { // <1>
logger.info("Placing orderId={} request={}", id, orderRequest);
public Effect<Order> placeOrder(@RequestBody OrderRequest orderRequest) { // <1>
var orderId = commandContext().entityId();
logger.info("Placing orderId={} request={}", orderId, orderRequest);
var newOrder = new Order(
id,
orderId,
false,
true, // <2>
orderRequest.item(),
orderRequest.quantity());
return effects()
.updateState(newOrder)
.thenReply(newOrder);
.updateState(newOrder)
.thenReply(newOrder);
}

@PostMapping("/confirm")
public Effect<String> confirm(@PathVariable String id) {
logger.info("Confirming orderId={}", id);
public Effect<String> confirm() {
var orderId = commandContext().entityId();
logger.info("Confirming orderId={}", orderId);
if (currentState().placed()) { // <3>
return effects()
.updateState(currentState().confirm())
.thenReply("Ok");
} else {
return effects().error(
"No order found for '" + id + "'",
"No order found for '" + orderId + "'",
ErrorCode.NOT_FOUND); // <4>
}
}

@PostMapping("/cancel")
public Effect<String> cancel(@PathVariable String id) {
logger.info("Cancelling orderId={} currentState={}", id, currentState());
public Effect<String> cancel() {
var orderId = commandContext().entityId();
logger.info("Cancelling orderId={} currentState={}", orderId, currentState());
if (!currentState().placed()) {
return effects().error(
"No order found for " + id,
"No order found for " + orderId,
ErrorCode.NOT_FOUND); // <5>
} else if (currentState().confirmed()) {
return effects().error(
Expand Down
Loading

0 comments on commit 8c7b5d2

Please sign in to comment.