Current section
Files
Jump to
Current section
Files
lib/fixerio.ex
defmodule Fixerio do
@moduledoc """
Provides access to Fixer.io like API with support for multiple endpoint
to use as fallback.
"""
import Fixerio.API
alias Fixerio.Config
@doc """
Gets the latest conversion rates. Uses the `/latest` API endpoint.
parameters:
* `options` (optioal): Map with optional keys `base` and `symbols`
Returns:
`%{ base: "USD", date: "2019-08-09", rates: %{ "AUD" => 1.46, "CZK" => 23.064, "IDR" => 14189.998, ... }}` in case of success
`{:error, %{errors: []}` in case of failure
## Examples
iex> Fixerio.get_latest %{base: :USD}
{:ok,
%{
base: "USD",
date: "2019-08-09",
rates: %{
"AUD" => 1.469190927,
"CZK" => 23.0648330059,
"IDR" => 14189.9982139668,
.
.
.
}
}}
iex> Fixerio.get_latest %{base: :USD}
{:error,
%{
errors: [
%{reason: "not found", url: "https://my-api.herokuapp.com"},
%{
reason: "Error. base_currency_access_restricted",
url: "http://data.fixer.io"
}
]
}}
iex> Fixerio.get_latest(%{symbols: [:AUD, :BRL, :CNY]})
{:ok,
%{
base: "USD",
date: "2019-08-09",
rates: %{"AUD" => 1.469190927, "BRL" => 3.9287372745, "CNY" => 7.0583139846}
}}
"""
def get_latest(options \\ %{base: :EUR}) do
base = if options[:base], do: options[:base], else: :USD
options = Map.put(options, :base, base)
request_with_fallback("latest", options)
end
@doc """
Coverts the given amount from the `from` currency to `to` currency, optionally
based on rate of a specific day.
parameters:
* `amount` (required): Integer - the amount to be converted
* `from` (required): Atom - current currency of the amount
* `to` (required): Atom - converted currency of the amount
* `date` (optional): Date - rate of the day to be used
Returns:
below data format in case of success
```
{:ok,
%{
date: "2019-08-09",
info: %{rate: 0.8930166101, timestamp: 1565380266},
query: %{amount: 90000, from: :USD, to: :EUR},
result: 80371.494909
}
}
```
or
`{:error, "Failed. No API available."}` in case of failure
## Examples
iex> Fixerio.convert(90000, :USD, :EUR)
{:ok,
%{
date: "2019-08-09",
info: %{rate: 0.8930166101, timestamp: 1565380266},
query: %{amount: 90000, from: :USD, to: :EUR},
result: 80371.494909
}}
"""
def convert(amount, from, to, date \\ nil) do
method = if date, do: Date.to_string(date), else: "latest"
options = %{base: from, symbols: [to]}
to_in_str = Atom.to_string(to)
case request_with_fallback(method, options) do
{:ok, %{date: date, rates: %{^to_in_str => rate}}} ->
data = %{
query: %{
from: from,
to: to,
amount: amount
},
info: %{
timestamp: DateTime.utc_now |> DateTime.to_unix(),
rate: rate
},
date: date,
result: amount * rate
}
{:ok, data}
{:error, _} ->
{:error, "Failed. No API available."}
end
end
@doc """
Gets the conversion rates on a day in past.
parameters:
* `date` (required): Date
* `options` (optioal): Map with optional keys `base` and `symbols`
Returns:
`%{ base: "USD", date: "2019-08-09", rates: %{ "AUD" => 1.46, "CZK" => 23.064, "IDR" => 14189.998, ... }}` in case of success
`{:error, %{errors: []}` in case of failure
## Examples
iex> Fixerio.historical_data(Date.utc_today)
{:ok,
%{
base: "EUR",
date: "2019-08-09",
rates: %{
"AUD" => 1.6452,
"BGN" => 1.9558,
"BRL" => 4.3994,
.
.
.
}
}}
"""
def historical_data(date, options \\ %{base: :EUR}) do
base = if options[:base], do: options[:base], else: :USD
options = Map.put(options, :base, base)
date = Date.to_string(date)
request_with_fallback(date, options)
end
def get_currencies do
# hard coded currecncies list
# thsi does not included extra currency data provided by fixer.io
[:USD,:AED,:ARS,:AUD,:BGN,:BRL,:BSD,:CAD,:CHF,:CLP,:CNY,:COP,:CZK,:DKK,:DOP,:EGP,:EUR,:FJD,:GBP,:GTQ,:HKD,:HRK,:HUF,:IDR,:ILS,:INR,:ISK,:JPY,:KRW,:KZT,:MXN,:MYR,:NOK,:NZD,:PAB,:PEN,:PHP,:PKR,:PLN,:PYG,:RON,:RUB,:SAR,:SEK,:SGD,:THB,:TRY,:TWD,:UAH,:UYU,:VND,:ZAR]
end
defp request_with_fallback(method, options) do
case request(method, options) do
{:ok, data} ->
{:ok, data}
{:error, reason} ->
error_lists = [%{url: Config.default_api[:url], reason: reason}]
result = Enum.reduce_while(Config.fallback_apis, [], fn api, err_list ->
options = Map.merge(options, %{url: api[:url], api_key: api[:api_key]})
case request(method, options) do
{:ok, data} ->
{:halt, {:ok, data}}
{:error, reason} ->
err_list = err_list ++ [%{url: options[:url], reason: reason}]
{:cont, err_list}
end
end)
case result do
{:ok, data} ->
{:ok, data}
[h | t] ->
errors = error_lists ++ [h | t]
{:error, %{errors: errors}}
_ ->
{:error, %{errors: [%{url: "all", reason: "Something went wrong"}]}}
end
end
end
end