{"id":16602214,"url":"https://github.com/rishav394/axon-labs-chat-application","last_synced_at":"2026-04-21T02:05:03.851Z","repository":{"id":125396279,"uuid":"327877870","full_name":"rishav394/axon-labs-chat-application","owner":"rishav394","description":"Axoniq labs chat application getting started's solution","archived":false,"fork":false,"pushed_at":"2021-01-11T10:05:58.000Z","size":22,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-01-17T08:45:09.051Z","etag":null,"topics":["axon-framework","cqrs"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rishav394.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-01-08T11:00:11.000Z","updated_at":"2021-01-11T10:06:01.000Z","dependencies_parsed_at":null,"dependency_job_id":"d1532914-cf10-4fe6-8b80-4e25e9e8bdb6","html_url":"https://github.com/rishav394/axon-labs-chat-application","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rishav394%2Faxon-labs-chat-application","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rishav394%2Faxon-labs-chat-application/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rishav394%2Faxon-labs-chat-application/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rishav394%2Faxon-labs-chat-application/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rishav394","download_url":"https://codeload.github.com/rishav394/axon-labs-chat-application/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":242692347,"owners_count":20170228,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["axon-framework","cqrs"],"created_at":"2024-10-12T00:21:02.441Z","updated_at":"2026-04-21T02:05:03.818Z","avatar_url":"https://github.com/rishav394.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"Axon Lab - Getting Started\n==========================\n\nSo, you're new to Axon and want to get started. Awesome!\n\nApplication overview\n--------------------\n\nThe main application is called `ChatGettingStartedApplication`. It's a Spring Boot application with \nthe following main dependencies:\n - Axon (Spring Boot starter)\n - Spring Data JPA\n - Freemarker\n - Web \n - Reactor\n - H2 (Embedded Database)\n - Spring Boot Test\n - Axon Test\n\nThere are a few test cases. One will check if the application can start, while the others \nvalidate the Aggregate's behavior. They should all fail, as most of the stuff needs yet to be implemented.\n\n### Application layout ###\n\nThe application's logic is divided among a number of packages.\n\n- `io.axoniq.labs.chat`  \n  The main package. Contains the Application class with the configuration.\n- `io.axoniq.labs.chat.commandmodel`  \n  Contains the Command Model. In our case, just the `ChatRoom` Aggregate that has been provided to make the project \n  compile.\n- `io.axoniq.labs.chat.coreapi`  \n  The so called *core api*. This is where we put the Commands, Events and Queries. \n  Since commands, events and queries are immutable, we have used Kotlin to define them. Kotlin allows you to\n  concisely define each event, command and query on a single line.  \n  To make sure you don't waste your precious time, we've implemented these Commands, Events and Queries for you.\n- `io.axoniq.labs.chat.query.rooms.messages`  \n  Contains the Projections (also called View Model or Query Model) for the Messages that have been broadcast in a \n  specific room. This package contains both the Event Handlers for updating the Projections, \n  as well as the Query Handlers to read the data.\n- `io.axoniq.labs.chat.query.rooms.participants`  \n  Contains the Projection to serve the list of participants in a given Chat Room. \n- `io.axoniq.labs.chat.query.rooms.summary`  \n  Contains the Projection to serve a list of available chat rooms and the number of participants.\n- `io.axoniq.labs.chat.restapi`  \n  This is the REST Command and Query API to change and read the application's state. \n  API calls here are translated into Commands and Queries for the application to process.\n\n### Swagger UI ###\nThe application has 'Swagger' enabled. You can use Swagger to send requests.\n\nVisit: [http://localhost:8080/swagger-ui/](http://localhost:8080/swagger-ui/)\n\n\u003cb\u003eNote\u003c/b\u003e: The Swagger UI does not support the 'Subscription Query' further on in the assignment,\n as Swagger does not support streaming results. \nIssuing a regular `curl` operation, or something along those lines, is recommended to check the Subscription Query.\n\n\u003cb\u003eNote 2\u003c/b\u003e: If you are on Intellij IDEA, you can also use the `command-request.http`\n and `query-request.http` files in this project to send requests directly from your IDE.\nSeveral defaults have been provided, but feel free to play around here!\n\n### H2 Console ###\nThe application has the 'H2 Console' configured, so you can peek into the database's contents.\n\nVisit: [http://localhost:8080/h2-console](http://localhost:8080/h2-console)  \nEnter JDBC URL: `jdbc:h2:mem:testdb:some_random_string_from_console` Check out the run console.  \nLeave other values to defaults and click 'connect'.\n\nPreparation\n-----------\n\nAxon Framework works best with AxonServer, and in this sample project we assume that you are using it. \nAxonServer needs to be downloaded separately.\nYou can run AxonServer as a docker container by running:\n```shell script\ndocker run -d -p 8024:8024 -p 8124:8124 -p 8224:8224 --name axonserver axoniq/axonserver\n```\n\nOur goal\n--------\n\nBasically, the goal is simple: make the tests pass!\n\nBut testing isn't the ultimate goal: we want to have an application that we can take into production.\n\nExercises\n---------\n\n### Implement the Command Model ###\n\nFirst of all, we're going to implement the Command Model. In this application, there is a single Aggregate: `ChatRoom`.\nThis aggregate processes Commands and produces Events as a result.\n\nThe expected behavior has been described in the `ChatRoomTest` class, using the Axon Test Fixtures.\n\nTo make these tests pass, you will need to implement the following command handlers:\n1. The handler for the `CreateRoomCommand` creates a new instance of a `ChatRoom`. \n   Therefore, this command handler is a constructor, instead of a regular method. \n   The method should `apply` (static method on `AggregateLifecycle`) a `RoomCreatedEvent`. \n   \n   Axon requires a no-arg constructor, we will also need to create one.\n\n   Axon requires one field to be present: the aggregate's identifier. \n   Create a field called roomId of type String, and annotate it with `@AggregateIdentifier`.\n    \n   We will also need to set this field to the correct value. \n   As we are using event sourcing, we must do so in an `@EventSourcingHandler`. \n   Create one that reacts to the `RoomCreatedEvent` and sets the `roomId` to the correct value.  \n2. The handler for the `JoinRoomCommand` should apply a `ParticipantJoinedRoomEvent`,\n    but only if the joining participant hasn't already joined this room. \n   Otherwise, nothing happens. To do this, we will need to maintain some state. \n   We do this in `@EventSourcingHandler`, remember? Create the required handlers.\n3. The handler for the `LeaveRoomCommand` should apply a `ParticipantLeftRoomEvent`,\n    but only if the leaving participant has joined the room. \n   Otherwise, again, nothing happens. \n   Don't forget to update state in the right location.\n4. Finally, implement the handler for the `PostMessageCommand`. \n   A participant may only post messages to rooms he/she has joined. \n   Otherwise, an exception is thrown.\n   \n    Now, there is only one thing left to do:\n\n5. We need to tell Axon that we want to configure this class as an Aggregate. \n   Annotate it with `@Aggregate` to have the Axon Spring Boot Auto-Configuration module configure\n    the necessary components to work with this aggregate.\n   \nThat's it. All tests should pass now. If not, implement the missing behavior and try again...\n \n### Connect the REST API to the Command Bus ###\n\nWe've got a component that can handle commands now. Now, it's time to allow external components to trigger these \ncommands. The `CommandController` class defines some API endpoints that should trigger commands to be sent.\n\nIn Axon, we can use either the Command Bus or the CommandGateway to send commands. \nThe latter has a friendlier API, so we've decided to use that one.\n\n 1. Implement the TODOs in the `CommandController` class to forward Commands to the Command Bus. \n    Note that the API Endpoint methods declare a return type of `Future\u003c...\u003e`. \n    The `CommandGateway.send()` method also returns a Future. \n    This is a nice way to prepare the API layer for asynchronous execution of commands (perhaps later).\n\n 2. The `CreateChatRoom` API declares an ID as part of the HTTP Entity it expects. \n    Although we generally favor client-generated identifiers, Javascript is notoriously bad at generating random values. \n    Therefore, we would want the `roomId` to default to a proper randomly generated UUID (use `UUID.randomUUID().toString()`). \n   \n    Note that this API Endpoint returns a `Future\u003cString\u003e` (as opposed to `Future\u003cVoid\u003e`). \n    Axon returns the identifier of an Aggregate as a result of a Command creating a new Aggregate instance. \n   \nThat's it! Once you're done, you should be able to start the application and send messages.\nRemember that [Swagger](http://localhost:8080/swagger-ui/) is in place to help with this.\nAdditionally, if you are on Intellij IDEA you can use the `command-request.http` file to execute some REST operations too.\n\nNote that the queries are not implemented yet. That's fixed in the next step.\n\n### Implement the Projections ###\n\nNow that the application is able to change state, it would be nice to expose that state. \nThis is done in projections.\n\nWe need to implement three projections for this application:\n  \n  1. The `ChatMessageProjection` exposes the list of messages for a given chat room. \n     Implement an `@EventHandler` for the `MessagePostedEvent`. \n     \n     Note that the `ChatMessage` Entity expects a timestamp. Axon attaches information to Events, which you can\n     access in the Event Handlers. Add an extra parameter: `@Timestamp Instant timestamp`. Axon will automatically \n     inject the timestamp at which the message was originally created. Use `timestamp.toEpochMilli()` to convert it to\n     milliseconds-since-epoch.\n     \n  2. Implement the `@EventHandler`s for the `RoomParticipantProjection`. This projection keeps track of all the \n     participants in each chatroom. You will need to implement an `@EventHandler` for each of the Events that describe \n     a change in the participants of a room...\n     \n  3. The last projection, the `RoomSummaryProjection`, gives us a summary of all the available chat rooms. The summary \n     contains the name of the room, and the number of participants in it. It's up to you to implement it.\n     \n  4. Implement the `@QueryHandler`s needed to extract data from all the projections. You will need to implement a    \n     `@QueryHandler` for each Query defined in *core api*. So, implement an `AllRoomsQuery` handler in \n     `RoomSummaryProjection`, a `RoomParticipantsQuery` handler in `RoomParticipantProjection`, and a \n     `RoomMessagesQuery` handler in `ChatMessageProjection`.\n \n  5. The projection `ChatMessageProjection` gives us a list of all the messages in a chat rooms. In order to support\n     a 'Subscription Query' we will need to use the `QueryUpdateEmitter`  in the `@EventHandler` to send an update for \n     each new chat message.\n\n### Connect the REST API to the Query Bus ###\n\nWe've got a component that can handle queries now. Now, it's time to allow external components to trigger these \nqueries. The `QueryController` class defines some API endpoints that should trigger queries to be sent.\n\nWe can use either the `QueryBus` or the `QueryGateway` to send queries. The latter has a friendlier API, so \nwe've decided to use that one.\n\n 1. Implement the TODOs in the `QueryController` class to forward Queries to the `QueryBus`. Note that the API \n    Endpoint methods declare a return type of `Future\u003c...\u003e`. The `QueryGateway.query()` method also returns a `Future`. \n 2. Note that `subscribeRoomMessages()` endpoint declares a return type of `Flux\u003c...\u003e`. In this service you can send a \n    Subscription Query, by using the `QueryGateway#subscriptionQuery(...)` method, instead of a regular query in order \n    to be notified about new messages sent into the room. \n\nWhen you think you're done, give the application a spin and see what happens...\nRemember, you can use [Swagger](http://localhost:8080/swagger-ui/)\n or the `query-request.http` (if you use Intellij IDEA) to test the new endpoints. \n\n# Done! Hurrah! #\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frishav394%2Faxon-labs-chat-application","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frishav394%2Faxon-labs-chat-application","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frishav394%2Faxon-labs-chat-application/lists"}