feat: implement IDR rate aggregator#197
Closed
joniheri wants to merge 9 commits intoallobankdev:mainfrom
Closed
Conversation
…egistry and in-memory store
…torical rate endpoints
- Add comprehensive PR description template with endpoints and testing guide - Reduce Frankfurter API timeouts (connect: 15s->5s, read: 20s->5s) for better responsiveness
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
feat: Implement IDR Rate Aggregator Backend Solution
Overview
This PR implements a complete Spring Boot solution for the Allo Bank Backend Developer take-home test, featuring a polymorphic REST API endpoint that aggregates data from the Frankfurter Exchange Rate API. The implementation demonstrates production-ready architecture with clean code, advanced Spring concepts, and comprehensive testing.
Key Features Implemented
1. Polymorphic API Endpoint
GET /api/finance/data/{resourceType}latest_idr_rates: Latest exchange rates with personalized IDR spread calculationhistorical_idr_usd: Historical IDR/USD rates for date range 2024-01-01..2024-01-05supported_currencies: Complete list of supported currency symbols2. Strategy Pattern Implementation
IDRDataFetcherwithresourceType()andfetch()methodsLatestIdrRatesFetcher: Handles latest rates with spread calculationHistoricalIdrUsdFetcher: Processes historical time series dataSupportedCurrenciesFetcher: Fetches currency symbolsIDRDataFetcherRegistryprovides Spring-injected map-based lookup3. Startup Data Preloading
FinanceDataPreloadRunner(implementsApplicationRunner)AtomicReferencefor immutability4. Client Factory Pattern
RestTemplateFactoryBeancreates and configuresRestTemplate@ConfigurationProperties5. Personalization & Business Logic
joniherijoniheri→ j(106) + o(111) + n(110) + i(105) + h(104) + e(101) + r(114) + i(105) = 856(1 / Rate_USD) * (1 + 0.00856)6. Production Readiness Features
application.yml/swagger-ui/index.htmlAvailable Endpoints
Core API Endpoints (Testable via Browser/Postman/cURL)
Home Endpoint
GET /{ "app": "allo-backend-test", "message": "Service is running", "endpoints": { "finance_data": "/api/finance/data/{resourceType}" } }curl http://localhost:8080/Finance Data Endpoint (Polymorphic)
GET /api/finance/data/{resourceType}resourceType(string) - One of:latest_idr_rates,historical_idr_usd,supported_currenciescurl http://localhost:8080/api/finance/data/latest_idr_ratescurl http://localhost:8080/api/finance/data/historical_idr_usdcurl http://localhost:8080/api/finance/data/supported_currencies{ "error": "Bad Request", "message": "Unsupported resourceType: invalid_type", "supportedResourceTypes": [ "latest_idr_rates", "historical_idr_usd", "supported_currencies" ] }Documentation & Testing Endpoints
Swagger UI
GET /swagger-ui/index.htmlOpenAPI JSON Specification
GET /v3/api-docscurl http://localhost:8080/v3/api-docsJaCoCo Test Coverage Report
GET /jacoco/(served fromtarget/site/jacoco/index.html)mvn test jacoco:report, opentarget/site/jacoco/index.htmlin browserArchitectural Rationale
1. Polymorphism Justification
The Strategy Pattern was chosen over conditional logic in the service layer to isolate each resource-fetching behavior into dedicated classes. This approach prevents the growth of complex if/else chains in the controller, improves extensibility (adding new resource types requires only new strategy classes), and maintains clean separation of concerns. Each strategy encapsulates its own data transformation logic, making the codebase more maintainable and testable.
2. Client Factory Benefits
Using
FactoryBean<RestTemplate>centralizes client creation and configuration in a dedicated component, providing explicit control over the client's lifecycle. This approach cleanly separates the concern of client construction from business logic classes and satisfies the requirement to avoid simple@Beanmethods for client creation.3. Startup Runner Choice
ApplicationRunnerwas selected over@PostConstructbecause it executes after full Spring context initialization and dependency wiring is complete. This ensures safer startup orchestration, provides clearer operational intent, and enables easier integration testing by allowing verification of data loading before the application context is fully ready.Testing & Validation
Automated Tests
FinanceDataServiceTest,FinanceDataStoreTest, strategy implementationsAlloBankTestApplicationTests(context loading)target/site/jacoco/Manual Testing Steps
Start the Application:
Wait for "Started AlloBankTestApplication" in logs (data preload completes here).
Test Core Endpoints:
View API Documentation:
Check Test Coverage:
mvn test jacoco:reportThen open
target/site/jacoco/index.htmlin browser to view coverage report.Import Postman Collection:
postman/allo-backend-test.postman_collection.jsonbaseUrlvariable tohttp://localhost:8080Expected Response Examples
latest_idr_rates:
{ "resourceType": "latest_idr_rates", "data": { "base": "EUR", "EUR": 1, "date": "2024-01-05", "rates": { "IDR": 17000.0, "USD": 1.08, "USD_BuySpread_IDR": 0.008568 } } }historical_idr_usd:
{ "resourceType": "historical_idr_usd", "data": { "base": "USD", "USD": 1, "quote": "IDR", "rates": [ { "date": "2024-01-01", "idr_per_usd": 15500.0 }, { "date": "2024-01-02", "idr_per_usd": 15550.0 } ] } }Configuration
Files Changed
Checklist
This implementation demonstrates advanced Spring Boot concepts, clean architecture, and production-ready code quality suitable for enterprise applications.