Design and implement a RESTful API (including data model and the backing implementation) for money transfers between accounts.
💰 Keep it simple and to the point (e.g. no need to implement any authentication).
💰 Assume the API is invoked by multiple systems and services on the behalf of end users.
💰 You can use frameworks/libraries if you like (except for Spring), but don't forget to keep it simple and avoid heavy frameworks.
💰 The data store should run in-memory for the sake of this test.
💰 The final result should be executable as a stand-alone program (should not require a pre-installed container/server).
💰 Demonstrate with tests that the API works as expected.
💰 The code produced by you is expected to be of high quality.
💰 There are no detailed requirements, use common sense.
💰 There is only one bank; Pete's World Banking Empire.
💰 Customers are allowed to open a new account with a zero balance.
💰 Transfers can only happen between accounts owned by the same customer.
💰 Transactions always clear immediately.
💰 All currency is in US Dollars (USD).
These instructions will get you a copy of this project up and running on your local machine. Once the REST service is running, see the API section for the available options.
- Clone this Git repository:
git clone https://github.com/peter-sattler/money-transfer-api
- Switch to the application directory:
cd money-transfer-api
- Run the integration tests:
./mvnw verify
- Run the program:
./mvnw exec:java
💰 Implemented using Jakarta RESTful Web Services (JAX-RS)
💰 Made use of Jersey's HK2 dependency injection framework
Action | Verb | Resource Locator (URL) | JSON Payload | Status Codes |
---|---|---|---|---|
Fetch bank details | GET | http://localhost:8080/api/v1/money-transfer/bank | 200 (Success) | |
Fetch all customers | GET | http://localhost:8080/api/v1/money-transfer/customers | 200 (Success) 404 (No customers found) |
|
Fetch a single customer | GET | http://localhost:8080/api/v1/money-transfer/customer/{id} | 200 (Success) 404 (Customer not found) |
|
Add a customer | POST | http://localhost:8080/api/v1/money-transfer/customer | { "id": "123-456", "firstName": "Barb", "lastName": "Wire", "gender": "FEMALE", "address": { "street": "55 Water St", "city": "New York", "state": "NY", "zip": 10004 }, "phone": "(212) 623-5089", "email": "barb.wire@fences.cow", "birthDate": "1963-10-28" } |
201 (Success) 409 (Customer exists) |
Delete a customer | DELETE | http://localhost:8080/api/v1/money-transfer/customer/{id} | 204 (Success) 404 (Customer not found) 409 (One or more accounts exist) |
|
Fetch all accounts | GET | http://localhost:8080/api/v1/money-transfer/accounts/{customerId} | 200 (Success) 404 (Customer not found) |
|
Fetch a single account | GET | http://localhost:8080/api/v1/money-transfer/account/{customerId}/{number} | 200 (Success) 404 (Customer or account not found) |
|
Add an account | POST | http://localhost:8080/api/v1/money-transfer/account | { "customerId": "123-456", "type":"CHECKING", "balance": 100.25 } |
201 (Success) 404 (Customer not found) 409 (Unable to add account) |
Delete an account | DELETE | http://localhost:8080/api/v1/money-transfer/account/{customerId}/{number} | 204 (Success) 404 (Customer or account not found) 409 (Non-zero balance) |
|
Account transfer | PUT | http://localhost:8080/api/v1/money-transfer/account/transfer | { "customerId": "123-456", "sourceNumber": 123, "targetNumber": 234, "amount": 50 } |
200 (Success) 404 (Customer, source or target account not found) 409 (Source and target accounts are the same or invalid transfer amount found) 412 (Concurrent update detected) |
💰 Send JSON payload instead of using query parameters
💰 Use account level locking
💰 Clarify behavior on account creation (JavaDoc only)
💰 Make idiomatic use of Java 8 Optional
💰 Use JCIP (Java Concurrency In Practice) annotations
💰 Fix CRLF
💰 Add integration test harness so API is fully covered
💰 Remove restricted class usage from the bootstrap utility
💰 Inject transfer service implementation using Jersey's HK2 dependency injection (DI) framework
💰 Added gender, address, phone, email, birth date, and joined date fields to Customer
💰 Added checking and savings account types
💰 Bootstrap utility now automatically loads customer and account data
💰 Renamed project from money-transfer to money-transfer-api
💰 Change customer ID from integer (primitive) to String to support social security number (SSN)
💰 Added Cross-Origin Resource Sharing (CORS) filter
💰 Added REST call to get all accounts for a customer id
💰 Automatically generate the account number for new accounts
💰 Added REST call to find a single account for a customer id
💰 BUG FIX - Add account location header should refer to the new account, not just its owner
💰 Created money transfer REST resource interface and moved annotations there
💰 Customers can only be deleted if they don't have any accounts
💰 Accounts can only be deleted it they have a zero balance
💰 Using regular expressions, check that the account number path parameter is numeric
💰 Check if source and target accounts are different before making a transfer
💰 Added HTTP 1.1 cache controls (no caching for now)
💰 Created a separate integration test harness for Bank, Customer and Account
💰 Check for concurrent updates during transfers
💰 Added concurrency test harness
💰 Return HTTP 404 when no customers are found
💰 Upgraded to Gradle 6.1.1
💰 Compiled using Java 13
💰 Do not use throws keyword on unchecked exceptions [Effective-Java-74]
💰 Remove Java serialization [Effective-Java-85]
💰 Use Maven instead of Gradle
💰 Upgraded to Java 17
Pete Sattler
March 2022
peter@sattler22.net