!!!Notice!!!: This project is now considered outdated as it is based on the old Akka (untyped) API. For a more up-to-date example using the new Akka Typed API, please refer to j5ik2o/akka-cqrs-es-example-typed. We strongly recommend checking out the updated version for a better understanding and implementation of the CQRS/ES pattern.
- DDD, CQRS + Event Sourcing based design
- Implement using Akka(-actor, -stream, -cluster-sharding, -persistence, -persistence-query, -http, ...)
- Scala 2.12.4
- REST API Application
- Bank Account to deposit/withdraw
- Deposit money to a Bank Account
- Withdraw money from a Bank Account
- Refer to deposits and withdraws in a Bank Account
In this project, the layered structure is based on 'Clean Architecture'.
- Domain objects are represented by case class.
- Domain types
- BankAccountId
- BankAccount
- BankAccountEventId
- BankAccountEvent
- BankAccountOpened is the account opening event
- BankAccountUpdateared is the account information updating event
- BankAccountDeposited is the deposit event
- BankAccountWithdrawn is the withdarw event
- BankAccountClosed is the account closed event
- Command use case is BankAccountAggregateUseCase
- Query use case is BankAccountReadModelUseCase
- BankAccountAggregate(PersistentActor)
- ShardedBankAccountAggregate(Extended BankAccountAggregate for cluster-sharding)
- ShardedBankAccountAggregates(proxy to ShardRegion)
The DAOs and Records are generated by septeni-original/sbt-dao-generator
$ sbt clean test
Terminal #1
$ sbt -DPORT=2551 -DHTTP_PORT=8080 'localMysql/run' 'api-server/run'
Terminal #2
$ sbt -DPORT=2552 -DHTTP_PORT=8081 'api-server/run'
Terminal #3
$ sbt -DPORT=2553 -DHTTP_PORT=8082 'api-server/run'
Terminal #4
$ sbt 'read-model-updater/run'
# open a bank account
$ curl -X POST \
http://localhost:$PORT/bank-accounts \
-H 'cache-control: no-cache' \
-H 'content-type: application/json' \
-d '{ "name": "test-1" }'
{"id":"XEe","errorMessage":null}%
# update the bank account
$ curl -X PUT \
http://localhost:8080/bank-accounts/XEe \
-H 'cache-control: no-cache' \
-H 'content-type: application/json' \
-d '{
"name": "test-2"
}'
{"id":"XEe","errorMessage":null}%
# deposit to the bank account
$ curl -X PUT \
http://localhost:8080/bank-accounts/XEe/events \
-H 'cache-control: no-cache' \
-H 'content-type: application/json' \
-d '{
"type": "deposit",
"amount": 1000,
"currencyCode": "JPY"
}'
{"id":"XEe","errorMessage":null}%
# withdraw from the bank account
$ curl -X PUT \
http://localhost:8080/bank-accounts/XEe/events \
-H 'cache-control: no-cache' \
-H 'content-type: application/json' \
-d '{
"type": "withdraw",
"amount": 500,
"currencyCode": "JPY"
}'
{"id":"XEe","errorMessage":null}%
# refer to events(deposits or withdraws) in the bank account
$ curl -X GET \
http://localhost:8080/bank-accounts/XEe \
-H 'cache-control: no-cache' \
-H 'content-type: application/json'
{
"id": "XEe",
"values": [
{
"type": "deposit",
"amount": 1000,
"currencyCode": "JPY",
"createAt": 1520219459
}
],
"errorMessage": null
}
# close the bank account
$ curl -X DELETE \
http://localhost:8080/bank-accounts/XEe \
-H 'cache-control: no-cache' \
-H 'content-type: application/json'
{
"id": "XEe",
"errorMessage": null
}
{"id":"XEe","errorMessage":null}%