REST Example to Query Weather API

While all of my coding so far has been self-contained within my Acumatica instance, I’ve heard that one of the great features of Acumatica is the ability to connect to external web services. At Hackathon 2019, my team did this by connecting to an external service called IFTTT (IF This Then That). The project was really cool and won one of the top 3 prizes, but I was still too new to C# to have any idea what was going on. For Hackathon 2020, with another year of experience under my belt, I found it a great time to catch up and learn how Acumatica can interact with an outside web service. While there is an entire Acumatica training devoted to connecting to Acumatica, this post will focus on Acumatica retrieving data from an external web service. For this example, I use Weather API.

Making a REST call to an external Web Service, as it turns out, is very easy. The hardest part of getting data is building the DAC’s to accept the data once it is retrieved from the service.

Building the REST call requires a few basic steps:

  • Add references to the project for Newtonsoft.Json and System.Net.Http if they are not already referenced
  • Register for an account with Weather API to get an API Key that enable you to access the data
  • Define the DAC’s required to deserialize the JSON data that will be retrieved
  • Build the method to execute the REST call using GET

Assuming you have taken the first 2 steps mentioned, let’s pick up with creating the DAC’s. You can do the research yourself, but for simplicity you can download the attached zip file containing the code used for this post here.

Since we are not going to access this data directly, the DAC’s can be very simple. However, you may notice that the data structures used by Weather API contain fields with an underscore, but Acumatica reserves underscore for a special use. Thanks to the help of one of my teammates this year, I learned that the [JsonProperty] attribute can be used to define the field name in the inbound JSON data and associate it to an Acumatica friendly field name. Notice the syntax on moon_phase and moon_illumination below.

using Newtonsoft.Json;

namespace Blog.BBWeather
{
    public class Astro
    {
        public string sunrise { get; set; }
        public string sunset { get; set; }
        public string moonrise { get; set; }
        public string moonset { get; set; }
        [JsonProperty("moon_phase")]
        public string moonphase { get; set; }
        [JsonProperty("moon_illumination")]
        public string moonillumination { get; set; }
    }
}

Once all of the DAC’s are defined in your project, we will move along to the Class and Method to execute the GET via REST. Review the sample code below, and then read on for an explanation of the key parts. If you download the code, you will see additional code for retrieving historical data as well. This has been shortened in the displayed example for simplicity.

using Newtonsoft.Json;
using System;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;

namespace Blog.BBWeather
{
    public class GetAPI
    {
        public static CurrentWeather MyCurrentWeather = new CurrentWeather();
        public static string APIKey = "InsertYourWeatherApiKeyHere";

        public static string Test()
        {
            int zipCode = 94558;  // Replace with your Zip Code
            string dateCode = string.Format("0:yyyy-MM-dd", DateTime.Today.AddDays(-1).ToString());

            GetCurrentWeather(zipCode).Wait();

            string currentInfo = String.Format(
                "Current ({0:MM/dd/yyyy hh:mm tt})\nLocation: {1}\nTemp: {2} F\nHumidity: {3}%",
                MyCurrentWeather.location.localtime,
                MyCurrentWeather.location.name,
                MyCurrentWeather.current.tempf,
                MyCurrentWeather.current.humidity
                );

            return currentInfo;
        }

        public async static Task<CurrentWeather> GetCurrentWeather(int zipcode)
        {
            var url = String.Format("http://api.weatherapi.com/v1/current.json?q={0}", zipcode);

            HttpClient client = new HttpClient();
            client.DefaultRequestHeaders.Add("key", APIKey);
            HttpResponseMessage response = await client.GetAsync(url);
            string content = await response.Content.ReadAsStringAsync();
            if (response.StatusCode == HttpStatusCode.OK)
            {
                CurrentWeather currentWeather = JsonConvert.DeserializeObject<CurrentWeather>(content);
                MyCurrentWeather = currentWeather;
                return currentWeather;
            }
            else
            {
                throw new Exception(content);
            }
        }

    }
}

Define properties to hold the API Key for Weather API and to hold the results. Be sure to fill in YOUR Weather API Key.

public static CurrentWeather MyCurrentWeather = new CurrentWeather();
public static string APIKey = "InsertYourWeatherApiKeyHere";

Define the method for the GET. In this case, we will pass in the Zip Code to select what geographic location to check. Also notice the signature of the GetCurrentWeather method. It is an async static method that returns Task<CurrentWeather>. Note that CurrentWeather is the type that we expect from the REST call. After reviewing the steps to accomplish below, read on to see the code that completes each of those steps. The actual GET call via REST is so simple that explaining takes longer than making the call.

  • Define the URL that we must access
  • Define an HttpClient to use
  • Add a DefaultRequestHeader to pass the API Key
  • Make the call with HttpResponseMessage response = await client.GetAsync(url);
  • Wait for the response and store it in the string “content”
  • Check the status of the call and throw an exception if not OK
  • Deserialize the JSON into a CurrentWeather object
  • Set the property MyCurrentWeather so that we can access it from the method that will initiate the REST call
  • Return the object that we retrieved
public async static Task<CurrentWeather> GetCurrentWeather(int zipcode)
{
	var url = String.Format("http://api.weatherapi.com/v1/current.json?q={0}", zipcode);

	HttpClient client = new HttpClient();
	client.DefaultRequestHeaders.Add("key", APIKey);
	HttpResponseMessage response = await client.GetAsync(url);
	string content = await response.Content.ReadAsStringAsync();
	if (response.StatusCode == HttpStatusCode.OK)
	{
		CurrentWeather currentWeather = JsonConvert.DeserializeObject<CurrentWeather>(content);
		MyCurrentWeather = currentWeather;
		return currentWeather;
	}
	else
	{
		throw new Exception(content);
	}
}

Define the method to execute the call. Notice the use of .Wait() to make the async call defined above. Since we are making an async call, we need to wait for it to complete and then retrieve the data from the property that was set by the async method. This example will create a string value of the Location, Temperature, and Humidity. You can use that value however you like when you make the call to your new Test() method.

public static string Test()
{
	int zipCode = 94558;  // Replace with your Zip Code
	string dateCode = string.Format("0:yyyy-MM-dd", DateTime.Today.AddDays(-1).ToString());

	GetCurrentWeather(zipCode).Wait();
	string currentInfo = String.Format(
		"Current ({0:MM/dd/yyyy hh:mm tt})\nLocation: {1}\nTemp: {2} F\nHumidity: {3}%",
		MyCurrentWeather.location.localtime,
		MyCurrentWeather.location.name,
		MyCurrentWeather.current.tempf,
		MyCurrentWeather.current.humidity
		);
	return currentInfo;
}

If everything is working properly, you should be able to get the weather by adding the following code in your customization:
string myWeather = Blog.BBWeather.GetAPI.Test();
This will return some values from the Current Weather via the Weather API REST call and place it in the string myWeather.

Of course, this code is simply an example. You may want to execute a PUT instead of a GET, and almost certainly handle the results much differently. Remember, the goal of the post was to show the basics to make a simple REST call. Now give it a try, and do a little web surfing or check out this link from Microsoft for more information: https://docs.microsoft.com/en-us/aspnet/web-api/overview/advanced/calling-a-web-api-from-a-net-client

Leave a Reply