Forex is an application that acts as a local proxy for getting exchange rates from third-party providers. Can be consumed by other internal services to ask the exchange rate between 2 given currencies and get back a rate that is not older than 5 minutes.
currency_1
andcurrency_2
are required query parameters being currency codes, e.g./rates?from=USD&to=EUR
- Currently the application supports exchange rates between any of
AUD
,CAD
,CHF
,EUR
,GBP
,NZD
,JPY
,SGD
,USD
- in case of an error, API provides a response with a list of error messages
application.conf
contains the following configs:
- of an external third-party to ask exchange rates from
- of an internal cache to keep exchange rates not older 5 minutes
- of rate limiting (throttling) of incoming requests
-
request
curl 'localhost:8080/rates?from=USD&to=EUR'
-
response
{"from":"EUR","to":"USD","price":{"value":0.50871114858135455},"timestamp":{"value":"2020-07-15T12:48:08.418+03:00"}}
-
request with unsupported currency
curl 'localhost:8080/rates?from=USD&to=UAH'
-
response
{"errors":["Exchange rate for UAH is not supported"]}
- App written with
Tagless Final pattern
in mind. - To meet the requirement of calling rate-limited third-party API:
- there is
app.external-service
config in theapplication.conf
where the one can configurehost
,port
,rate-limit-refresh-period-seconds
,limit-for-period
,auth-token-name
(to be present in the HTTP header),auth-token-value
- used resilience4j to get rate-limiting functionality and its RateLimiter
- implemented
forex.services.ratelimiter.GetRateRequestLimiter
able to control a number of outbound requests throughRateLimiter
and depending on the above rate-limiting configs.
- there is
- To meet the requirement of providing back to the user an exchange rate which is not older 5 minutes and to decrease a number of
outbound requests towards third-party:
- implemented
forex.services.cache.OneFrameRatesCache
class which able to keep rates that being removed automatically after an expiration period. Number of rates to keep and expiration are configured values inapplication.cong
(app.rates-cache
) - to have caching functionality under the hood, used ScalaCache, its Caffeine implementation and Cats-effect support.
- implemented
- To support an ability of rate-limiting own REST API:
- implemented
forex.http.rates.middleware.ratelimiter.IncomingRequestsLimiter
able to control a number of inbound requests throughresilience4j
'sRateLimiter
and depending onapp.throttling
configs inapplication.conf
. IncomingRequestsLimiter
is composed in the application middleware.
- implemented
- Http4s Client used for calling third-party via REST API.
- Since there is no
one-frame
REST API specification and only known that200 OK
response returned with an array of rates, there are following implemented assumptions:- external API may return a successful response with the array of rates for a given currencies pair -
taken into account only the 1st rate in the array. Forex proxy returns
200 OK
with a rate. - external API may return a successful response with an empty array for a given currencies pair. Forex proxy
returns
404 NotFound
with an error message. - external API may return any unsuccessful response. Forex proxy returns
400 BadRequest
with an error message.
- external API may return a successful response with the array of rates for a given currencies pair -
taken into account only the 1st rate in the array. Forex proxy returns
- Since there is no specification of
one-frame
supported currencies:- for any unsupported by Forex app currency, it responds
400 BadRequest
with an error message. - in case
one-frame
returns an empty array for a given pair, Forex app responds404 NotFound
with an error message.
- for any unsupported by Forex app currency, it responds
- Due to a library versions conflict with
Http4s Client
,fs2
was downgraded to version1.0.5
. - Unit tests written in Table-driven checks style.