A financial transaction service built with Node.js, Express, and DynamoDB. Handles concurrent transactions with race condition protection and idempotency guarantees.
demo.mp4
- Concurrent transaction safety using DynamoDB conditional writes
- Idempotency protection with unique transaction keys
- Real-time balance management with consistency guarantees
- Comprehensive error handling for edge cases
- Automatic user provisioning for testing
- Runtime: Node.js with TypeScript
- Framework: Express.js
- Database: Amazon DynamoDB (Local for development)
- Testing: Jest
- Package Manager: npm
- Node.js (v16 or higher)
- Docker
- DynamoDB Local
- Install dependencies:
npm install- Start DynamoDB Local:
npm run docker:up- Start the application:
npm run devThe server starts on http://localhost:3000 and automatically creates the necessary tables and a default user (default-user) with $100 balance.
GET /balance/:userIdResponse:
{
"userId": "default-user",
"balance": 100
}POST /transact
Content-Type: application/json
{
"idempotentKey": "unique-transaction-id-123",
"userId": "default-user",
"amount": 50,
"type": "credit" | "debit"
}Response:
{
"message": "Transaction unique-transaction-id-123 completed successfully."
}GET /Interactive testing interface available at http://localhost:3000
Run tests:
npm testRun race condition tests:
npm test -- --testNamePattern="race condition"- Uses DynamoDB conditional writes to prevent concurrent transaction conflicts
- Ensures only one of multiple simultaneous transactions can succeed when funds are insufficient
- Each transaction requires a unique
idempotentKey - Duplicate requests with the same key return the same result without side effects
| Error | Status | Description |
|---|---|---|
InsufficientFundsError |
400 | Debit exceeds available balance |
UserNotFoundError |
404 | User does not exist |
IdempotencyKeyViolationError |
409 | Duplicate transaction key |
InvalidTransactionError |
400 | Invalid transaction parameters |
