Introduction to implementing Views in Kalix

background
Reading Time: 3 minutes

Introduction

There are mainly 3 building blocks in any Kalix application – Entities, Views, and Actions. Views, as the name suggests, are responsible for viewing the data. Although we can fetch data using the entity_key defined in the domain, we use Views for more flexibility and customization.

This blog is a brief discussion on Views with a Value-Entity in Kalix and how we can use them in our application.

Note: To read about the basics of gRPC and Entities visit the following links
1. gRPC Descriptors
2. Types of entities in Kalix
3. Event Sourced entities in Kalix (1) (2)

Creating a View in Kalix

To create a View, we must follow the following steps:

a) Create a domain file
The domain file represents the data that the View will display i.e., domain files are the source of data for a View. We also require this domain file for the second step which uses these domain models to perform operations like CRUD

message TodoItemState {

  string item_id = 1;

  string title = 2;

  string description = 3;

  string added_by = 4;

  bool done = 5;
}

b) Create a service for an Entity (can be Value Entity, Event Sourced Entity) defined in the domain file above. This service defines the remote procedure calls that are responsible for producing state changes for the Value-Entity

service TodoListService {

  option (kalix.codegen) = {

    value_entity: {

      name: "todolist.domain.TodoItem",

      entity_type: "todolist",

      state: "todolist.domain.TodoItemState"
    }
  };


  rpc AddItem(TodoItem) returns (google.protobuf.Empty) {

    option (google.api.http) = {

      post: "/todoitem/add"

      body: "*"
    };
  }


  rpc GetItemById(GetItemByIdRequest) returns (TodoItem) {

    option (google.api.http) = {

      get: "/todoitem/{item_id}"
    };
  }

  // Can add more such RPC Calls
}


message TodoItem {

  string item_id = 1 [(kalix.field).entity_key = true];

  string title = 2;

  string description = 3;

  string added_by = 4;

  bool done = 5;
}


message GetItemByIdRequest {

  string item_id = 1 [(kalix.field).entity_key = true];
}

c) Creating a View for the domain defined above. We use this View to query information based on our custom implementation.

  • Informing the code generator that a view needs to be created
  • Next, we define a method that basically links our domain model with a table. This allows Kalis to update the table when there is a change in the state of the domain.
  • Next, we define another method responsible for fetching records from the table we define in the previous step. We use SQL queries here to get records
service TodoListByName {

  option(kalix.codegen) = {

    view: {}

  };


  rpc UpdateTodoList(domain.TodoItemState) returns (domain.TodoItemState) {

    option(kalix.method).eventing.in = {

      value_entity: "todolist"

    };

    option(kalix.method).view.update = {

      table: "todolist"
    };
  }


  rpc GetTodoListItems(GetByNameRequest) returns (stream 

domain.TodoItemState) {

    option(kalix.method).view.query = {

      query: "SELECT * FROM todolist where added_by = :name"
    };
  }

}


message GetByNameRequest {

    string name = 1;
}

d) At last, we have to register our View in the main class. This is a kind of binding and is a necessary step without which our View will not be shown.

  def createKalix(): Kalix = {

    KalixFactory.withComponents(

      new TodoItem(_),

      new TodoListByNameView(_))
  }

CQRS

CQRS stands for Command Query Responsibility Segregation. From its name, we can infer that it discusses segregating or differentiating responsibilities for querying (SELECT) records from tables and inserting/updating/deleting them from the table.

Kalix also follows the CQRS principle. The entities are responsible for creating, updating, and deleting records, and the Views are accountable for the querying part as we have seen above.

There are 2 sides in CQRS – The read side and the Write side. The Write side is responsible for storing the state changes and the read side retrieves data. Thus changing the state of View does not happen in the same transaction as changing/ persisting of state. Kalix projects these changes in the states onto the Views.

In Kalix, state changes occur in the state store (for value entities) or the event journal (for event-sourced entities). There is a time delay in state changes and when that data is queryable

Conclusion

The data layer part in Kalix is entirely abstracted and as developers, we don’t have access to how this is implemented internally. Nonetheless, we can take advantage of the CQRS pattern, especially in enterprise applications where there is more reading activity than writing activity and Views are the means to achieve.

References:
To read more visit the Official Kalix Documentation page
GitHub link to the complete source code provided above
To read about Kalix and its advantages visit here

Leave a Reply