Please check the REQUIREMENTS.md to review the goal of this project.
- API Docs:
{baseUrl}/v3/api-docs
- Swagger UI:
{baseUrl}/swagger-ui/index.html
BASE_URL=http://localhost:8080/api
View all available currency symbols
curl "$BASE_URL/symbols"
Exchange 10 USD to PHP
curl "$BASE_URL/exchange?base=USD&target=PHP&amount=10"
Exchange 1.5 AED to JPY
curl "$BASE_URL/exchange?base=AED&target=JPY&amount=1.5"
- Java 11
- API key from https://exchangeratesapi.io
- Use
fake
provider if you do not want to sign up. See "Changing Providers" section.
- Use
- Docker engine - optional if you want to run the application via Gradle
# unix
./gradlew build
# win
gradlew.bat build
Docker
Please ensure that the application is already built. See "Build" section for more details.
# perform build first
docker compose up
Please provide your access token in the .env file. Or run it with
# unix
FX_API_KEY=<YOUR_TOKEN_HERE> docker compose up
# win
SET FX_API_KEY=<YOUR_TOKEN_HERE>
docker compose up
If you encounter => ERROR [...] COPY build/libs/fx-rates-api*.jar fx-rates-api.jar
, then that means the application is not yet built.
Please check the "Build" section.
Gradle
You can run the application without performing the Gradle build
task.
# unix
FX_API_KEY=<YOUR_TOKEN_HERE> ./gradlew bootRun
# win
SET FX_API_KEY=<YOUR_TOKEN_HERE>
gradlew.bat bootRun
There are two providers for both the rate and symbols. The default provider is exchangeratesapi.io
.
- FREE plan
- There’s a limit to the number of requests per month
- For the full list of limitations, please check their documentation.
- We can't change the base currency, but we can use the list of rates with one base. The implication is that we have to derive our own rate. If the base currency of the provider has changed, the application will adapt.
EUR
is the base of the provider at the time of the development.
- Only supports limited rates. See the table below for the mappings.
Base | Target | Rate |
---|---|---|
USD | PHP | 52.17 |
PHP | USD | 0.019 |
AED | JPY | 93.49 |
JPY | AED | 0.011 |
EUR | GBP | 0.83 |
GBP | EUR | 1.21 |
The rates provided from the table is just a fake data, and not necessarily precise, this fake provider is only useful
for testing the behavior of our service. They are just for demonstration purposes, and querying USD
to AED
for
instance will not work, as there is no mapping between them. Please use the exchangeratesapi.io
provider if you want to test with multiple currencies.
Check "Changing Providers" section on how to change a provider.
This is the default provider. Check the "Running" section.
You can change it to a fake
provider by changing the active profile to local
.
Docker
docker compose --env-file ./config/.env.local up
Gradle
# unix
SPRING_PROFILES_ACTIVE=local ./gradlew bootRun
# win
SET SPRING_PROFILES_ACTIVE=local
gradlew.bat bootRun
To verify the current provider in use. Call the /api/provider
endpoint.
BASE_URL=localhost:8080/api
curl "$BASE_URL/provider"
- Buying and selling currencies will both use the
/api/exchange
endpoint. Both of them will providebase
,target
, and theamount
, just in different context.- For instance, when a user wants to BUY
USD
to another party, and they want to spend 10PHP
, they will have/api/exchange?base=PHP&target=USD&amount=10
. - If they are going to SELL 100
PHP
to another party withAED
currency, they will have/api/exchange?base=PHP&target=AED&amount=100
.
- For instance, when a user wants to BUY
- We are only exposing three endpoints.
GET /api/exchange
- the only responsibility of this endpoint is to provide the value based from the derivedrate
ofbase
andtarget
currency. Selling and buying foreign currency can both use this endpoint, they just need to switch out thebase
andtarget
.GET /api/symbols
- lists supported currency symbolsGET /api/provider
- to easily verify what provider is in use.- exchange rates - default provider
- fake provider - provides limited symbols and rates
- Here are some improvements/considerations for future development
- More logs and control
- Cached data are stored in memory, this can be improved by using a Redis or a similar service.
- Better handling of Access Token, we can set up a config server for the application bootstrap
- Ability to configure API timeouts
- Rate limiting and rate throttling
- Better API client design for future work if required, but right now, we only want to build URLs based on a path, it limits building complex queries.