0

I've read numerous threads asking similar questions but have been unable to tie it all together.

I have an API feeding a string here: https://apiv2.bitcoinaverage.com/constants/exchangerates/local

I would like to make this string usable and accessible. For example getting the USD to CAD rate.

I'm using RestSharp and Newtonsoft JSON in my code.

using Newtonsoft.Json;
using RestSharp;

First I used http://json2csharp.com/ to create a class (classes?) matching the string. EDIT: I've now solved this, and had to nest the classes properly, as per revised code;

class Exrates
{
    public Rates rates { get; set; }
    public string time { get; set; }

    public class Rates
    {
        public MXN Mxn { get; set; }
        public ILS Ils { get; set; }
        public EUR Eur { get; set; }
        public BRL Brl { get; set; }
        public PLN Pln { get; set; }
        public MYR Myr { get; set; }
        public SEK Sek { get; set; }
        public AUD Aud { get; set; }
        public IDR Idr { get; set; }
        public TRY Try { get; set; }
        public RUB Rub { get; set; }
        public JPY Jpy { get; set; }
        public CAD Cad { get; set; }
        public USD Usd { get; set; }
        public GBP Gbp { get; set; }
        public NZD Nzd { get; set; }
        public CZK Czk { get; set; }
        public SGD Sgd { get; set; }

    public class MXN
        {
            public string name { get; set; }
            public string rate { get; set; }
        }

        public class ILS
        {
            public string name { get; set; }
            public string rate { get; set; }
        }

        public class EUR
        {
            public string name { get; set; }
            public string rate { get; set; }
        }

        public class BRL
        {
            public string name { get; set; }
            public string rate { get; set; }
        }

        public class PLN
        {
            public string name { get; set; }
            public string rate { get; set; }
        }

        public class MYR
        {
            public string name { get; set; }
            public string rate { get; set; }
        }

        public class SEK
        {
            public string name { get; set; }
            public string rate { get; set; }
        }

        public class AUD
        {
            public string name { get; set; }
            public string rate { get; set; }
        }

        public class IDR
        {
            public string name { get; set; }
            public string rate { get; set; }
        }

        public class TRY
        {
            public string name { get; set; }
            public string rate { get; set; }
        }

        public class RUB
        {
            public string name { get; set; }
            public string rate { get; set; }
        }

        public class JPY
        {
            public string name { get; set; }
            public string rate { get; set; }
        }

        public class CAD
        {
            public string name { get; set; }
            public string rate { get; set; }
        }

        public class USD
        {
            public string name { get; set; }
            public string rate { get; set; }
        }

        public class GBP
        {
            public string name { get; set; }
            public string rate { get; set; }
        }

        public class NZD
        {
            public string name { get; set; }
            public string rate { get; set; }
        }

        public class CZK
        {
            public string name { get; set; }
            public string rate { get; set; }
        }

        public class SGD
        {
            public string name { get; set; }
            public string rate { get; set; }
        }
    }
}

I then called the API and stored the response in a string;

    var btcAvgClient = new RestClient();
    btcAvgClient.BaseUrl = new Uri("https://apiv2.bitcoinaverage.com/constants/exchangerates/local");

    IRestResponse response;
    var request = new RestRequest();

    response = btcAvgClient.Execute(request);
    string btcAvg = response.Content;

I believe there are 1 or 2 steps remaining but I can't quite figure it out. How do I now convert this string to something usable?

Any help is appreciated!

Sterlingz
  • 1
  • 1
  • 2
  • 1
    You can deserialize `rates` into a `Dictionary` as shown in [Deserializing JSON when key values are unknown](https://stackoverflow.com/a/24901245/3744182) or [Deserializing JSON with unknown object names](https://stackoverflow.com/q/38688570/3744182) or [Create a strongly typed c# object from json object with ID as the name](https://stackoverflow.com/a/34213724/3744182) or [Parsing JSON Object with variable properties into strongly typed object](https://stackoverflow.com/q/34202496/3744182). – dbc Dec 31 '18 at 18:58

2 Answers2

1

Firstly, modify your data model to look like the following:

public class Rate
{
    public string name { get; set; }
    public decimal rate { get; set; }
}

public class RootObject
{
    public Dictionary<string, Rate> rates { get; set; }
    public string time { get; set; }
}

Next, introduce the following extension method:

public static partial class RateExtensions
{
    public static bool TryGetConversion(this Dictionary<string, Rate> rates, string from, string to, out decimal rate)
    {
        Rate fromRate;
        Rate toRate;

        if (rates == null || !rates.TryGetValue(from, out fromRate))
        {
            rate = 0;
            return false;
        }

        if (!rates.TryGetValue(to, out toRate))
        {
            rate = 0;
            return false;
        }

        rate = toRate.rate / fromRate.rate;
        return true;
    }
}

Now, you can execute a typed request as follows. The typed request will automatically deserialize the response into your desired data model:

var btcAvgClient = new RestClient("https://apiv2.bitcoinaverage.com/");
var request = new RestRequest("constants/exchangerates/local");

// Execute the request and get the typed response
var response = btcAvgClient.Execute<RootObject>(request);

// Get the root object from the response.
RootObject data = response.Data;

And compute the conversion from USD to CAD as follows:

// Compute the converson from (e.g.) USD to CAD
var fromName = "USD";
var toName = "CAD";

decimal rate;
if (data.rates.TryGetConversion(fromName, toName, out rate))
{
    Console.WriteLine("Conversion from {0} to {1} = {2}", fromName, toName, rate);
}
else
{
    Console.WriteLine("Cannot get conversion from {0} to {1}.", fromName, toName);
}

On my computer this outputs

Conversion from USD to CAD = 1.36245

Which currently seems to be the correct number as confirmed by a Google search:

1 United States Dollar equals 1.36 Canadian Dollar

Notes:

  • Since this API might possibly return different currencies in the future, but with the same data for each, I defined rates to be a Dictionary<string, Rate> rates. The dictionary will capture all returned currency rates.

    Your code will need to know the currency names to expect, but I believe these are standard.

  • Since we are doing currency conversions here I defined rate to be a decimal rather than a string. The serializer will automatically deserialize the string value for "rate" into a decimal.

  • To ensure your request was successful see How to idiomatically handle HTTP error codes when using RestSharp?.

    Alternatively you could check the response.ErrorException as shown in the Recommended Usage documentation page.

  • If you need to make async requests see How should I implement ExecuteAsync with RestSharp on Windows Phone 7?.

  • RestSharp has a built-in JSON serializer but you could use Json.NET if you prefer. Simply get the response.Content string and deserialize by doing:

    // Execute the request and get the untyped (string) response
    var response = btcAvgClient.Execute(request);
    
    // Get the root object from the response.
    RootObject data = Newtonsoft.Json.JsonConvert.DeserializeObject<RootObject>(response.Content);
    
dbc
  • 104,963
  • 20
  • 228
  • 340
  • Thanks for your help! I'm a beginner and am having problems understanding your code, but it's coming along nicely. I ended up solving the above, but will circle back to your code at some point to improve my own implementation. Once again I appreciate your help. – Sterlingz Jan 04 '19 at 01:21
0

Should be too root object.

var beers = JsonConvert.DeserializeObject<RootObject>(response.Content);
dbc
  • 104,963
  • 20
  • 228
  • 340
Ryan Schlueter
  • 2,223
  • 2
  • 13
  • 19