This project implements a Currency Exchange Rate API using a Clean Architecture approach. It aims to deliver high code readability and maintainability by decoupling responsibilities, applying dependency injection, and enabling comprehensive unit testing.
This project manages currencies and exchange rates and includes endpoints to retrieve currency details, convert amounts between currencies, and retrieve historical exchange rate time series. The implementation follows Clean Architecture principles to keep the core business logic independent of external frameworks and delivery mechanisms.
The project is organized into distinct layers:
-
Entities (Domain):
Represent the business objects of the application. For example,CurrencyEntity
andCurrencyExchangeRateEntity
encapsulate the essential attributes and behaviors associated with currencies and exchange rates. -
Use Cases / Interactors (Services):
Business logic is encapsulated in service classes (interactors) such asCurrencyInteractor
andCurrencyExchangeRateInteractor
. These classes orchestrate domain operations, applying business rules and interacting with repositories. -
Interfaces / Repository Interfaces:
This layer defines contracts for data persistence and external services. Repository interfaces abstract away the details of how data is stored and accessed.- Database Repositories: Implemented using Django's ORM, they handle CRUD operations on models.
- Cache Repositories: Utilize Redis (via Django’s caching framework) to store and retrieve frequently accessed data.
-
Adapters / Controllers:
Django Rest Framework ViewSets act as adapters. They bridge the HTTP layer with the use cases by translating HTTP requests into method calls on interactors. Serializers validate and transform data between JSON and domain entities. -
Dependency Injection:
CurrencyRepositoryFactory
create and inject the dependencies by instantiating lower-level components (e.g., database and cache repositories) and composing them together. They are decoupled by injecting repository implementations into interactor classes. This allows easy substitution with mocks during testing and better separation between business logic and infrastructure concerns.
- Backend Framework: Django
- API Framework: Django Rest Framework
- Background Tasks: Celery
- Relational Database: PostgreSQL
- Cache Service: Redis
- Testing: Pytest and unittest.mock
The codebase follows a layered structure inspired by Clean Architecture:
├── src
│ ├── domain
│ │ └── exchange_rate.py # Domain entities and business rules
│ ├── usecases
│ │ └── exchange_rate.py # Interactors implementing business logic
│ ├── infrastructure
│ │ ├── orm
│ │ │ ├── db
│ │ │ │ ├── exchange_rate
│ │ │ │ │ ├── models.py # Django ORM models
│ │ │ │ │ └── repositories.py # Database repository implementations
│ │ │ │ └── cache
│ │ │ │ │ └── exchange_rate
│ │ │ │ │ └── repositories.py # Cache repository implementations
│ ├── interface
│ │ ├── controllers
│ │ │ └── exchange_rate.py # API controllers / viewsets (DRF)
│ │ ├── repositories
│ │ │ └── exchange_rate.py # Repository interface definitions
│ │ └── serializers
│ │ └── exchange_rate.py # Data validation & transformation for API payloads
├── tests # Unit and integration tests
└── README.md
- Endpoint: GET
/api/currencies/<code>/
- Description: Retrieves details of a currency based on its code.
- Response Example:
{ "code": "USD", "name": "US Dollar", "symbol": "$" }
- Endpoint: GET
/api/exchange-rate-convert/
- Query Parameters:
source_currency
: Code of the source currency.exchanged_currency
: Code of the target currency.amount
: Amount to convert.
- Description: Converts an amount from one currency to another using the latest exchange rate.
- Response Example:
{ "exchanged_currency": "EUR", "exchanged_amount": 89.75, "rate_value": 0.8975 }
- Endpoint: GET
/api/exchange-rate-list/
- Query Parameters:
source_currency
: Code of the source currency.date_from
: Start date in YYYY-MM-DD format.date_to
: End date in YYYY-MM-DD format.
- Description: Returns a list of historical exchange rate records.
- Response Example:
[ { "source_currency": "USD", "exchanged_currency": "EUR", "valuation_date": "2023-01-05", "rate_value": 0.8987 }, { "source_currency": "USD", "exchanged_currency": "EUR", "valuation_date": "2023-01-15", "rate_value": 0.9023 } ]
- Endpoint: GET
/api/exchange-rate-calculate-twr/
- Query Parameters:
source_currency
: Code of the source currency.exchanged_currency
: Code of the target currency.date_from
: Start date in YYYY-MM-DD format.date_to
: End date in YYYY-MM-DD format.
- Description: Calculates the time-weighted average exchange rate over a specific period.
- Response Example:
{ "time_weighted_rate": 0.9001 }
curl -X GET "http://localhost:8000/api/currencies/USD/"
curl -G "http://localhost:8000/api/exchange-rate-convert/" \
--data-urlencode "source_currency=USD" \
--data-urlencode "exchanged_currency=EUR" \
--data-urlencode "amount=100"
curl -G "http://localhost:8000/api/exchange-rate-list/" \
--data-urlencode "source_currency=USD" \
--data-urlencode "date_from=2023-01-01" \
--data-urlencode "date_to=2023-01-31"
curl -G "http://localhost:8000/api/exchange-rate-calculate-twr/" \
--data-urlencode "source_currency=USD" \
--data-urlencode "exchanged_currency=EUR" \
--data-urlencode "date_from=2023-01-01" \
--data-urlencode "date_to=2023-01-31"