Customer Registry in Java
In this sample, you will learn how to create a customer registry with the Java SDK, package it into a container, and run it on Kalix.
In this sample you will learn:
-
How to add additional functionality, allowing customers to be queried by name and email.
-
How to package the customer registry into a container.
-
How to deploy and run the customer registry on Kalix.
Before you begin
-
If you’re new to Kalix, create an account, so you can try out Kalix for free.
-
You’ll need to install the Kalix CLI to deploy from a terminal window.
-
You’ll also need
-
Java 17 or higher
If you want to bypass writing code and jump straight to the deployment:
|
Generate and build the Kalix project
The Maven archetype template prompts you to specify the project’s group ID, name and version interactively. Run it using the commands shown for your OS.
Follow these steps to generate and build your project:
-
From a command window, run the template in a convenient location:
- Linux or macOS
-
mvn archetype:generate \ -DarchetypeGroupId=io.kalix \ -DarchetypeArtifactId=kalix-spring-boot-archetype \ -DarchetypeVersion=1.5.5
- Windows 10+
-
mvn archetype:generate ^ -DarchetypeGroupId=io.kalix ^ -DarchetypeArtifactId=kalix-spring-boot-archetype ^ -DarchetypeVersion=1.5.5
-
Navigate to the new project directory.
-
Open it on your preferred IDE / Editor.
Customer Registry Service
The service contains only one Value Entity that exposes the operation to mutate a Customer model. The entity itself exposes service endpoints and eventually encapsulates some basic validation. The incoming commands/request are then applied to the model and the entity instructs Kalix, through the Effect
API what needs to be done next.
Define the domain model
First, define the domain classes in package customer.domain
.
package customer.domain;
public record Customer(String email, String name, Address address) { (1)
public Customer withName(String newName) { (2)
return new Customer(email, newName, address);
}
public Customer withAddress(Address newAddress) { (2)
return new Customer(email, name, newAddress);
}
}
1 | Define a Java record email , name and Address . |
2 | Defined methods implementing the mutations. Note that both methods return a new version of the Customer record and only modify one field. |
Finally, the Address
record.
package customer.domain;
public record Address(String street, String city) {}
Define the external API
The Customer
API is defined by the CustomerEntity
.
Create a class named CustomerEntity
in package customer.api
.
import kalix.javasdk.valueentity.ValueEntity;
import kalix.javasdk.annotations.Id;
import kalix.javasdk.annotations.TypeId;
import org.springframework.web.bind.annotation.*;
import io.grpc.Status;
import customer.domain.Address;
import customer.domain.Customer;
@TypeId("customer") (1)
@Id("customer_id") (2)
@RequestMapping("/customer/{customer_id}") (3)
public class CustomerEntity extends ValueEntity<Customer> { (4)
@PostMapping("/create") (5)
public ValueEntity.Effect<String> create(@RequestBody Customer customer) {
if (currentState() == null)
return effects()
.updateState(customer) (6)
.thenReply("OK"); (7)
else
return effects().error("Customer exists already");
}
@GetMapping()
public ValueEntity.Effect<Customer> getCustomer() {
if (currentState() == null)
return effects().error(
"No customer found for id '" + commandContext().entityId() + "'",
Status.Code.NOT_FOUND
);
else
return effects().reply(currentState());
}
@PostMapping("/changeName/{newName}")
public Effect<String> changeName(@PathVariable String newName) {
Customer updatedCustomer = currentState().withName(newName);
return effects()
.updateState(updatedCustomer)
.thenReply("OK");
}
@PostMapping("/changeAddress")
public Effect<String> changeAddress(@RequestBody Address newAddress) {
Customer updatedCustomer = currentState().withAddress(newAddress);
return effects().updateState(updatedCustomer).thenReply("OK");
}
}
1 | Each Entity needs a unique logical type name. This must be unique per Kalix service. |
2 | The entity needs to be address by a unique identifier. The @Id declares the name of the path variable that Kalix should use as unique identifier. |
3 | The @RequestMapping defines the base path to access the entity. Note that the {customer_id} matches the value of @Id . |
4 | CustomerEntity must inherit from kalix.javasdk.valueentity.ValueEntity . |
5 | Each API method must be exposed as a REST endpoint using Spring’s REST annotations. |
6 | The implementation instructs Kalix to persist the state customer . |
7 | After persisting, Kalix is instructed to return the String 'Ok'. |
Package and deploy your service
To build and publish the container image and then deploy the service, follow these steps:
-
If you haven’t done so yet, sign in to your Kalix account. If this is your first time using Kalix, this will let you register an account, create your first project, and set this project as the default.
kalix auth login
-
Use the
deploy
target to build the container image, publish it to the container registry as configured in thepom.xml
file, and the targetkalix:deploy
to automatically deploy the service to Kalix:mvn deploy kalix:deploy
If you time stamp your image. For example, <dockerTag>${project.version}-${build.timestamp}</dockerTag>
you must always run both targets in one pass, i.e.mvn deploy kalix:deploy
. You cannot runmvn deploy
first and thenmvn kalix:deploy
because they will have different timestamps and thus different `dockerTag`s. This makes it impossible to reference the image in the repository from the second target. -
You can verify the status of the deployed service using:
kalix service list
Invoke your service
Once the service has started successfully, you can start a proxy locally to access the service:
kalix service proxy <service name>
You can use command line HTTP clients, such as curl
or httpie
, to invoke the service through the proxy at localhost:8080
, using plaintext connections.
A customer can be created using the /customer/{customer_id}/create
endpoint on CustomerEntity
:
curl localhost:8080/customer/abc123/create \
--header "Content-Type: application/json" \
-XPOST \
--data '{
"email": "someone@example.com",
"name": "Someone",
"address": {
"street": "123 Some Street",
"city": "Somewhere"
}
}'
The /customer/abc123
endpoint can be used to retrieve this customer:
curl localhost:8080/customer/abc123
You can expose the service to the internet. A generated hostname will be returned from the expose command:
kalix service expose <service name>
Try to call the exposed service with curl
:
curl https://<generated hostname>/customer/abc123
Next steps
-
You can learn more about Value Entities.
-
Continue this example by adding Views, which makes it possible to query the customer registry.