Money transfers API backend.
- Controller behind HTTP endpoints can receive commands or queries.
- Command or query is then forwarded to actor.
- Actor replies with results for the query if query is sent to it.
- When command is sent to actor,
- Actor validates command.
- Command can be rejected with error
- Accepted commands become events.
- Events trigger state updates.
- Create account
- Deposit
- Withdraw
- Transfer
Kotlin
- Javalin (HTTP)
- Akka actor (State management)
- Kotlin test (Testing)
- Jackson (Json)
- Slf4j (Logging)
Base package is com.moneytx.
MoneyTxApp.kt is the entry point of this app and has main method declared.
Domain models, exceptions, validations, events and commands are
declared in domain package.
Application logic and state management goes into logic package.
Controller receives command/query objects from routes.
Command/Query objects are forwarded from controller to command actor.
- Queries get answered at this stage.
- Commands get validated, commands can get rejected.
- Accepted commands become events and are sent to event handler.
Event handler interprets the event and updates the state which is inside the actor in a thread-safe manner.
docker build -t moneytx .docker run -p 8080:8080 --rm moneytxIn the project root, use following commands
./gradlew compileKotlin
./gradlew build./gradlew test./gradlew run --args=9090Note: First value from args is considered as port number.
Default port number is 8080.
curl -X GET \
http://localhost:8080/createAccount \
-H 'Accept: */*' \
-H 'Accept-Encoding: gzip, deflate' \
-H 'Cache-Control: no-cache' \
-H 'Connection: keep-alive' \
-H 'Content-Type: application/json' \
-H 'Host: localhost:8080' \
-H 'cache-control: no-cache'Result:
{"id":"3a93fe91-12e2-4741-bd7f-63fa398c4a74","currentBalance":{"value":0}}%
curl -X POST \
http://localhost:8080/deposit \
-H 'Accept: */*' \
-H 'Accept-Encoding: gzip, deflate' \
-H 'Cache-Control: no-cache' \
-H 'Connection: keep-alive' \
-H 'Content-Length: 103' \
-H 'Content-Type: application/json' \
-H 'Host: localhost:8080' \
-H 'Postman-Token: 4fcb1074-0722-4cd1-9c47-2c7c15e3d390,0d4433b2-3f49-4af5-8c0a-7f4cfeaae3b9' \
-H 'User-Agent: PostmanRuntime/7.20.1' \
-H 'cache-control: no-cache' \
-d '{
"accountId": {
"value": "3a93fe91-12e2-4741-bd7f-63fa398c4a74"
},
"amount": {
"value": 20
}
}'
Result:
{"id":"3a93fe91-12e2-4741-bd7f-63fa398c4a74","currentBalance":{"value":20}}%
curl -X POST \
http://localhost:8080/withdraw \
-H 'Accept: */*' \
-H 'Accept-Encoding: gzip, deflate' \
-H 'Cache-Control: no-cache' \
-H 'Connection: keep-alive' \
-H 'Content-Length: 103' \
-H 'Content-Type: application/json' \
-H 'Host: localhost:8080' \
-H 'cache-control: no-cache' \
-d '{
"accountId": {
"value": "3a93fe91-12e2-4741-bd7f-63fa398c4a74"
},
"amount": {
"value": 10
}
}'
Result:
{"id":"3a93fe91-12e2-4741-bd7f-63fa398c4a74","currentBalance":{"value":10}}%
[Documents] curl -X POST \
http://localhost:8080/transfer \
-H 'Accept: */*' \
-H 'Accept-Encoding: gzip, deflate' \
-H 'Cache-Control: no-cache' \
-H 'Connection: keep-alive' \
-H 'Content-Length: 169' \
-H 'Content-Type: application/json' \
-H 'Host: localhost:8080' \
-H 'cache-control: no-cache' \
-d '{
"accountId": {
"value": "3a93fe91-12e2-4741-bd7f-63fa398c4a74"
},
"amount": {
"value": 10
},
"payee": {
"value": "9bd85943-7cac-4e3f-907a-cfa97f621daf"
}
}'
Result:
{"id":"3a93fe91-12e2-4741-bd7f-63fa398c4a74","currentBalance":{"value":0}}%