RESTful API for money transfers between accounts.
- Java 11
Alternatively project can be build and run with Docker.
Service is using maven wrapper, so there is no need in having maven in the execution environment.
- Database is running completely in memory. After the application is stopped, all the data will be lost.
- For simplicity all amounts are in cents and without a currency.
- Data consistency is guaranteed by append-only approach for storing the data and usage of idempotency keys.
Scripts to populate database schema are applied during the application startup using flyway. For convenience classes required by jOOQ are pre-generated and stored in a separate source root, to not to be mixed with the application sources. In case there are changes to the database schema jOOQ classes can be re-generated using the following command:
./mvnw -Pjooq-generate
To run unit and integration tests execute the following command:
./mvnw clean verify
Build an executable jar:
./mvnw clean package
Then run it:
java -jar ./target/service-jar-with-dependencies.jar
By default server is running on port 7000
. It can be changed using server.port
system property, e.g.:
java -Dserver.port=8080 -jar ./target/service-jar-with-dependencies.jar
First run may take some time. Provided image is not optimized for any kind of workload and can only be used for testing.
First build an image:
docker build -t transfer-service:latest .
Start the container using the following command:
docker run --rm -it -p 7000:7000 transfer-service:latest
There is an e2e test that shows the whole flow.
All provided examples are using HTTPie for making calls.
Request: POST /api/v1/accounts
Request body: No
Example:
As soon as application is using in-memory database, accounts for testing have to be first created. To created a new account the following command can be used:
http --verbose POST :7000/api/v1/accounts
The output of the command should be similar to the following:
HTTP/1.1 201 Created
Content-Length: 0
Content-Type: application/json
Date: Sun, 08 Sep 2019 20:41:57 GMT
Location: /api/v1/accounts/09bba65c-763d-4fe4-b687-f4aee07c88c2
Server: Javalin
Location
header in the response contains an ID of a newly created account.
Request: GET /api/v1/accounts/:account_id
Request body: No
Example:
Information about an account can be obtained using the following command:
http --verbose GET :7000/api/v1/accounts/09bba65c-763d-4fe4-b687-f4aee07c88c2
The output of the command should be similar to the following:
HTTP/1.1 200 OK
Content-Length: 57
Content-Type: application/json
Date: Sun, 08 Sep 2019 20:47:55 GMT
Server: Javalin
{
"balance": 0,
"id": "09bba65c-763d-4fe4-b687-f4aee07c88c2"
}
Newly created accounts always have a 0
balance.
Request: POST /api/v1/accounts/:account_id/credit-transactions
Request body: JSON document with the following properties
id
- id of the credit transaction. It is used for idempotency. It should be a new random UUID every time.amount
- amount to credit in cents.
Example:
Account balance can be topped-up by creating a credit transaction to it:
http --verbose POST :7000/api/v1/accounts/09bba65c-763d-4fe4-b687-f4aee07c88c2/credit-transactions id=e49cec55-90de-4076-8f8e-98a6a43ad0a5 amount:=20000
The output of the command should be similar to the following:
HTTP/1.1 200 OK
Content-Length: 0
Content-Type: application/json
Date: Sun, 08 Sep 2019 20:53:50 GMT
Server: Javalin
Request: POST /api/v1/transfers
Request body: JSON document with the following properties
id
- id of the transfer. It is used for idempotency. It should be a new random UUID every time.source_account_id
- id of the source account. It will be debited.target_account_id
- id of the target account. It will be credited.amount
- amount to transfer in cents.
Example:
To transfer money between two previously created accounts the following command can be used:
http --verbose POST :7000/api/v1/transfers id=aa8050b2-8fb2-4854-ba98-61278fb5e95a source_account_id=09bba65c-763d-4fe4-b687-f4aee07c88c2 target_account_id=b838bf5a-7277-4874-baae-a87dd4868a0b amount:=10000
The output of the command should be similar to the following:
HTTP/1.1 200 OK
Content-Length: 0
Content-Type: application/json
Date: Sun, 08 Sep 2019 21:04:21 GMT
Server: Javalin
After a successful transfer, new balances can be observed by querying the account information endpoint:
http --verbose GET :7000/api/v1/accounts/09bba65c-763d-4fe4-b687-f4aee07c88c2
The output shows a new balance of a source account:
HTTP/1.1 200 OK
Content-Length: 61
Content-Type: application/json
Date: Sun, 08 Sep 2019 21:13:32 GMT
Server: Javalin
{
"balance": 10000,
"id": "09bba65c-763d-4fe4-b687-f4aee07c88c2"
}