Currency exchange rates is an interesting financial dataset similar to stock quotes and cryptocurrency datasets. For building solutions like software or a POS system for a currency exchange business it is a necessary dataset and there are APIs online that give you easy access to this data. One API that is available is from ExchangeRatesAPI.io which is owned by apilayer (a sister company of Embarcadero). The API is easy to use and it is even easier to build cross-platform currency exchange rate solutions with RAD Studio and Delphi for Windows, Android, iOS, macOS, and Linux with a single codebase and single UI.

Delphi (and RAD Studio) includes a tool called the REST Debugger where you can configure all of your REST API settings and then export them as components into your Delphi application. This includes wiring up the incoming data automatically to an in memory database table (TFDMemTable). It literally takes only a few minutes to get up and running with the API from ExchangeRatesAPI.io from within Delphi and RAD Studio. Let’s dive into the ExchangeRatesAPI.io API and see how to build a desktop and mobile application utilizing it’s REST API.

How can I get currency exchange rates with an API?

The two important API calls which will be used in this project are (full documentation available here):

https://api.exchangeratesapi.io/v1/symbols?access_key=API_KEY – This first API call returns a list of all available currencies including a symbol and full name for each.

{
    "success": true,
    "symbols": {
        "AED": "United Arab Emirates Dirham",
        "AFN": "Afghan Afghani",
        "ALL": "Albanian Lek",
        "AMD": "Armenian Dram",
        "ANG": "Netherlands Antillean Guilder",
        "AOA": "Angolan Kwanza",
        "ARS": "Argentine Peso",
        "AUD": "Australian Dollar",
        "AWG": "Aruban Florin",
        "AZN": "Azerbaijani Manat",
        "BAM": "Bosnia-Herzegovina Convertible Mark",
        "BBD": "Barbadian Dollar",
        "BDT": "Bangladeshi Taka",
        "BGN": "Bulgarian Lev",
        "BHD": "Bahraini Dinar",
        "BIF": "Burundian Franc",
        "BMD": "Bermudan Dollar",
        "BND": "Brunei Dollar",
        "BOB": "Bolivian Boliviano",
        "BRL": "Brazilian Real",
        "BSD": "Bahamian Dollar",
        "BTC": "Bitcoin",
        "BTN": "Bhutanese Ngultrum",
        "BWP": "Botswanan Pula",
        "BYN": "New Belarusian Ruble",
        "BYR": "Belarusian Ruble",
        "BZD": "Belize Dollar",
        "CAD": "Canadian Dollar",
        "CDF": "Congolese Franc",
        "CHF": "Swiss Franc",
        "CLF": "Chilean Unit of Account (UF)",
        "CLP": "Chilean Peso",
        "CNY": "Chinese Yuan",
        "COP": "Colombian Peso",
        "CRC": "Costa Rican Colón",
        "CUC": "Cuban Convertible Peso",
        "CUP": "Cuban Peso",
        "CVE": "Cape Verdean Escudo",
        "CZK": "Czech Republic Koruna",
        "DJF": "Djiboutian Franc",
        "DKK": "Danish Krone",
        "DOP": "Dominican Peso",
        "DZD": "Algerian Dinar",
        "EGP": "Egyptian Pound",
        "ERN": "Eritrean Nakfa",
        "ETB": "Ethiopian Birr",
        "EUR": "Euro",
        "FJD": "Fijian Dollar",
        "FKP": "Falkland Islands Pound",
        "GBP": "British Pound Sterling",
        "GEL": "Georgian Lari",
        "GGP": "Guernsey Pound",
        "GHS": "Ghanaian Cedi",
        "GIP": "Gibraltar Pound",
        "GMD": "Gambian Dalasi",
        "GNF": "Guinean Franc",
        "GTQ": "Guatemalan Quetzal",
        "GYD": "Guyanaese Dollar",
        "HKD": "Hong Kong Dollar",
        "HNL": "Honduran Lempira",
        "HRK": "Croatian Kuna",
        "HTG": "Haitian Gourde",
        "HUF": "Hungarian Forint",
        "IDR": "Indonesian Rupiah",
        "ILS": "Israeli New Sheqel",
        "IMP": "Manx pound",
        "INR": "Indian Rupee",
        "IQD": "Iraqi Dinar",
        "IRR": "Iranian Rial",
        "ISK": "Icelandic Króna",
        "JEP": "Jersey Pound",
        "JMD": "Jamaican Dollar",
        "JOD": "Jordanian Dinar",
        "JPY": "Japanese Yen",
        "KES": "Kenyan Shilling",
        "KGS": "Kyrgystani Som",
        "KHR": "Cambodian Riel",
        "KMF": "Comorian Franc",
        "KPW": "North Korean Won",
        "KRW": "South Korean Won",
        "KWD": "Kuwaiti Dinar",
        "KYD": "Cayman Islands Dollar",
        "KZT": "Kazakhstani Tenge",
        "LAK": "Laotian Kip",
        "LBP": "Lebanese Pound",
        "LKR": "Sri Lankan Rupee",
        "LRD": "Liberian Dollar",
        "LSL": "Lesotho Loti",
        "LTL": "Lithuanian Litas",
        "LVL": "Latvian Lats",
        "LYD": "Libyan Dinar",
        "MAD": "Moroccan Dirham",
        "MDL": "Moldovan Leu",
        "MGA": "Malagasy Ariary",
        "MKD": "Macedonian Denar",
        "MMK": "Myanma Kyat",
        "MNT": "Mongolian Tugrik",
        "MOP": "Macanese Pataca",
        "MRO": "Mauritanian Ouguiya",
        "MUR": "Mauritian Rupee",
        "MVR": "Maldivian Rufiyaa",
        "MWK": "Malawian Kwacha",
        "MXN": "Mexican Peso",
        "MYR": "Malaysian Ringgit",
        "MZN": "Mozambican Metical",
        "NAD": "Namibian Dollar",
        "NGN": "Nigerian Naira",
        "NIO": "Nicaraguan Córdoba",
        "NOK": "Norwegian Krone",
        "NPR": "Nepalese Rupee",
        "NZD": "New Zealand Dollar",
        "OMR": "Omani Rial",
        "PAB": "Panamanian Balboa",
        "PEN": "Peruvian Nuevo Sol",
        "PGK": "Papua New Guinean Kina",
        "PHP": "Philippine Peso",
        "PKR": "Pakistani Rupee",
        "PLN": "Polish Zloty",
        "PYG": "Paraguayan Guarani",
        "QAR": "Qatari Rial",
        "RON": "Romanian Leu",
        "RSD": "Serbian Dinar",
        "RUB": "Russian Ruble",
        "RWF": "Rwandan Franc",
        "SAR": "Saudi Riyal",
        "SBD": "Solomon Islands Dollar",
        "SCR": "Seychellois Rupee",
        "SDG": "Sudanese Pound",
        "SEK": "Swedish Krona",
        "SGD": "Singapore Dollar",
        "SHP": "Saint Helena Pound",
        "SLL": "Sierra Leonean Leone",
        "SOS": "Somali Shilling",
        "SRD": "Surinamese Dollar",
        "STD": "São Tomé and Príncipe Dobra",
        "SVC": "Salvadoran Colón",
        "SYP": "Syrian Pound",
        "SZL": "Swazi Lilangeni",
        "THB": "Thai Baht",
        "TJS": "Tajikistani Somoni",
        "TMT": "Turkmenistani Manat",
        "TND": "Tunisian Dinar",
        "TOP": "Tongan Paʻanga",
        "TRY": "Turkish Lira",
        "TTD": "Trinidad and Tobago Dollar",
        "TWD": "New Taiwan Dollar",
        "TZS": "Tanzanian Shilling",
        "UAH": "Ukrainian Hryvnia",
        "UGX": "Ugandan Shilling",
        "USD": "United States Dollar",
        "UYU": "Uruguayan Peso",
        "UZS": "Uzbekistan Som",
        "VEF": "Venezuelan Bolívar Fuerte",
        "VND": "Vietnamese Dong",
        "VUV": "Vanuatu Vatu",
        "WST": "Samoan Tala",
        "XAF": "CFA Franc BEAC",
        "XAG": "Silver (troy ounce)",
        "XAU": "Gold (troy ounce)",
        "XCD": "East Caribbean Dollar",
        "XDR": "Special Drawing Rights",
        "XOF": "CFA Franc BCEAO",
        "XPF": "CFP Franc",
        "YER": "Yemeni Rial",
        "ZAR": "South African Rand",
        "ZMK": "Zambian Kwacha (pre-2013)",
        "ZMW": "Zambian Kwacha",
        "ZWL": "Zimbabwean Dollar"
    }
}

https://api.exchangeratesapi.io/v1/latest?access_key=API_KEY&base=USD – This second API call returns real-time exchange rate data from the USD currency to all other currencies which gets updated every 60 minutes, every 10 minutes, or every 60 seconds.

{
    "success": true,
    "timestamp": 1618443847,
    "base": "EUR",
    "date": "2021-04-14",
    "rates": {
        "AED": 4.401602,
        "AFN": 92.987438,
        "ALL": 123.189782,
        "AMD": 622.325441,
        "ANG": 2.150997,
        "AOA": 771.454377,
        "ARS": 111.049893,
        "AUD": 1.550998,
        "AWG": 2.156941,
        "AZN": 2.046165,
        "BAM": 1.960773,
        "BBD": 2.419639,
        "BDT": 101.557685,
        "BGN": 1.956108,
        "BHD": 0.4518,
        "BIF": 2355.859391,
        "BMD": 1.198301,
        "BND": 1.602747,
        "BOB": 8.262446,
        "BRL": 6.775187,
        "BSD": 1.198391,
        "BTC": 1.9067596e-5,
        "BTN": 90.06308,
        "BWP": 13.096988,
        "BYN": 3.135003,
        "BYR": 23486.695865,
        "BZD": 2.415529,
        "CAD": 1.499979,
        "CDF": 2391.808752,
        "CHF": 1.105916,
        "CLF": 0.030816,
        "CLP": 850.318038,
        "CNY": 7.824422,
        "COP": 4381.9464,
        "CRC": 734.603479,
        "CUC": 1.198301,
        "CUP": 31.754971,
        "CVE": 110.932648,
        "CZK": 25.94405,
        "DJF": 212.962255,
        "DKK": 7.437344,
        "DOP": 68.255016,
        "DZD": 158.571629,
        "EGP": 18.777483,
        "ERN": 17.976802,
        "ETB": 49.55004,
        "EUR": 1,
        "FJD": 2.452563,
        "FKP": 0.870416,
        "GBP": 0.869667,
        "GEL": 4.140164,
        "GGP": 0.870416,
        "GHS": 6.926206,
        "GIP": 0.870416,
        "GMD": 61.113259,
        "GNF": 11983.008607,
        "GTQ": 9.248383,
        "GYD": 250.707366,
        "HKD": 9.305333,
        "HNL": 28.903569,
        "HRK": 7.57158,
        "HTG": 97.906362,
        "HUF": 358.507893,
        "IDR": 17515.083611,
        "ILS": 3.931206,
        "IMP": 0.870416,
        "INR": 89.904135,
        "IQD": 1751.316633,
        "IRR": 50454.456016,
        "ISK": 151.714206,
        "JEP": 0.870416,
        "JMD": 179.460912,
        "JOD": 0.849552,
        "JPY": 130.510579,
        "KES": 127.98481,
        "KGS": 101.611855,
        "KHR": 4847.126741,
        "KMF": 492.801162,
        "KPW": 1078.470959,
        "KRW": 1338.046775,
        "KWD": 0.361276,
        "KYD": 0.998693,
        "KZT": 516.331626,
        "LAK": 11287.993862,
        "LBP": 1825.846885,
        "LKR": 241.461698,
        "LRD": 206.832071,
        "LSL": 17.555151,
        "LTL": 3.538271,
        "LVL": 0.72484,
        "LYD": 5.410369,
        "MAD": 10.702619,
        "MDL": 21.535088,
        "MGA": 4535.568261,
        "MKD": 61.636388,
        "MMK": 1689.632611,
        "MNT": 3415.939059,
        "MOP": 9.586206,
        "MRO": 427.793183,
        "MUR": 49.357594,
        "MVR": 18.514034,
        "MWK": 943.661381,
        "MXN": 24.066602,
        "MYR": 4.947184,
        "MZN": 73.899259,
        "NAD": 17.5549,
        "NGN": 455.949342,
        "NIO": 42.036495,
        "NOK": 10.054341,
        "NPR": 144.100848,
        "NZD": 1.677843,
        "OMR": 0.461273,
        "PAB": 1.198391,
        "PEN": 4.348335,
        "PGK": 4.229665,
        "PHP": 58.092767,
        "PKR": 183.160095,
        "PLN": 4.554208,
        "PYG": 7547.686137,
        "QAR": 4.363013,
        "RON": 4.926575,
        "RSD": 117.877158,
        "RUB": 91.127306,
        "RWF": 1171.339041,
        "SAR": 4.494591,
        "SBD": 9.559982,
        "SCR": 18.14974,
        "SDG": 455.955933,
        "SEK": 10.143077,
        "SGD": 1.600804,
        "SHP": 0.870416,
        "SLL": 12252.625895,
        "SOS": 699.807988,
        "SRD": 16.960723,
        "STD": 24839.742882,
        "SVC": 10.486172,
        "SYP": 1506.944044,
        "SZL": 17.554312,
        "THB": 37.538567,
        "TJS": 13.664046,
        "TMT": 4.206036,
        "TND": 3.287535,
        "TOP": 2.735603,
        "TRY": 9.677839,
        "TTD": 8.146733,
        "TWD": 33.952055,
        "TZS": 2778.859514,
        "UAH": 33.497945,
        "UGX": 4315.378685,
        "USD": 1.198301,
        "UYU": 52.971442,
        "UZS": 12589.347994,
        "VEF": 256232928513.0559,
        "VND": 27655.584381,
        "VUV": 131.260508,
        "WST": 3.033771,
        "XAF": 657.576278,
        "XAG": 0.047174,
        "XAU": 0.00069,
        "XCD": 3.238468,
        "XDR": 0.841171,
        "XOF": 660.854586,
        "XPF": 120.009287,
        "YER": 299.994695,
        "ZAR": 17.244269,
        "ZMK": 10786.147736,
        "ZMW": 26.585877,
        "ZWL": 385.853094
    }
}

As you can see these are pretty straightforward APIs to get both a list of the available currencies and a list of real-time (or delayed) conversion rates from one of the currencies to the rest of the currencies.

How do I connect to the ExchangeRatesAPI.io API REST end point with Delphi?

This is what it looks like by taking the first API call above and plugging it into the REST Debugger in Delphi. You’ll notice how the JSON Root Element field is set to symbols. That takes the symbols element in JSON and makes it the root element to turn into the in-memory table dataset.

restdebugexchange-6873188

Once you have made the API call how you want it you can click the Copy Components button and then paste that into the application form in the Delphi IDE. It will create a TRESTClient, TRESTRequest, TRESTResponse, TRESTResponseDatasetAdapter, and TFDMemTable. This can be done for both of the API calls listed above. You can actually right click on the TRESTRequest component at this point and select Execute to execute the REST request at design time and fill the TFDMemTable with data so that you can use LiveBindings to bind the data to other controls.

exchangerightclick-2411413

How can I pivot the dataset of an TFDMemTable in Delphi?

In the case of this API the response data is in the form of a JSON object so each item is a column instead of the data being in the form of a JSON array which would have made each item a row. I prefer to have each item as a row so I perform a simple pivot of the data using the following code with the data from the /symbols API call. The TmpCurrencyMemTable contains the data directly from the REST request and all of the items are in columns. The CurrencyMemTable is the pivoted version of the data. You can see there is a for loop that loops through the fields of the TmpCurrencyMemTable and then appends their names and value to the CurrencyMemTable one record at a time.

CurrencyMemTable.EmptyDataSet;
    for var I := 0 to TmpCurrencyMemTable.Fields.Count-1 do
    begin
      CurrencyMemTable.AppendRecord([TmpCurrencyMemTable.Fields.Fields[I].FieldName,TmpCurrencyMemTable.Fields.Fields[I].Value])
    end;

The same operation is done for the second /latest API query with the TmpExchangeMemTable and the ExchangeMemTable.

ExchangeRateMemTable.EmptyDataSet;
    for var I := 0 to TmpExchangeMemTable.Fields.Count-1 do
    begin
      ExchangeRateMemTable.AppendRecord([TmpExchangeMemTable.Fields.Fields[I].FieldName,TmpExchangeMemTable.Fields.Fields[I].Value])
    end;

Now that we have covered the two API calls in the application and how to create components automatically for those two API calls lets take a look at the demo application.

How can I build a Windows desktop application?

We have a TLayout bar at the top with a Menu button and a Refresh button. Additionally, we gave a TEdit in the middle which features the value Base value for the /latest API call. There is a TMultiView setup on the left as a pushing drawer which pushes the TStringGrid on the right. The TMultiView contains a TListBox which holds the pivoted data from the /symbols API call. It is controlled by the Menu button. The TStringGrid contains the pivoted data results from the /latest API call. At the bottom of the view there are some TLabels which display the current Base value and the selected conversion value (in this case 1 USD equals 44.21 UYZ).

exchangedemo-5414496

How can I customize the format of LiveBindings text?

LiveBindings is used to fill the TLabels at the bottom of the window. The CustomFormat property is used to format the display of the two labels. The TListBox and the TStringGrid data is also filled via LiveBindings. The first CustomFormat you can see concatenates 3 strings together with %s representing the original value of the dataset field.

'1 ' + %s + ' ='

The second LiveBindings CustomFormat concatenates 4 strings together with the Self.Owner.FieldByName(‘CurrencyValue’).Text code accessing the CurrencyValue field and the Self.Owner.FieldByName(‘Symbol’).Text code accessing the Symbol field from the dataset.

' ' + Self.Owner.FieldByName('CurrencyValue').Text + ' ' + Self.Owner.FieldByName('Symbol').Text

In this article we have demonstrated how to build a Windows 10 desktop application to access a list of currencies and a list of the latest exchange rates in relation to all of the other currencies. The desktop application is using the Delphi FireMonkey framework which supports Android, iOS, macOS, Windows, and Linux with a single codebase and responsive UI. The same application demoed here can also run on the other 4 platforms. We’ve shown how easy it is to access a REST API in Delphi and how to access the APIs from ExchangeRatesAPI.io. Lastly, we’ve show how to pivot the data and livebind it to the visual controls within the application.

Check out the full source code for accessing currency exchange rates via a REST API on GitHub.

Head over and get your own free API key for the currency exchange rates API.