DEV Community

loading...
Cover image for Azure Functions, APIs, and the Weather
Bit Project

Azure Functions, APIs, and the Weather

TheDirector23
・6 min read

I wanted to create a program that answers the question “What should you do tomorrow?” based on the weather forecast. The goal was to help people come up with creative things to do tomorrow and plan out their day. Often, we fall back on the same activities or, if it's a nice day, find out we're too late to book something. Then we have regrets.

This was one of the first multi-layered coding projects I’d ever tackled, but it’s pretty simple with the right API and Azure Functions. In this tutorial blog, I’ve split the work into three parts: the webpage, the HTTP trigger, and the JavaScript.

Alt Text

What you’ll need:

  • A Microsoft Azure subscription (you can get one for free for a limited time)
  • An account at openweather.org (this is totally free for the API we’re using unless you want to upgrade)
  • Visual Studio Code (and to make things easier, install the Live Server extension – for testing your webpage along the way – the Azure Functions extension, and the Azure App Service extension)

Part #1: The Webpage

This is the easiest part because the webpage is relatively simple. The most important section is creating the div and form elements for the submission form. You need one overall div (I used the id “container”), inside of which is a hidden div (id “hidden-weather”) and a form element (id “zipcode-form”).

<div id="container">

        <div id="hidden-weather" type="hidden"></div>

        <form id="zipcode-form" onsubmit="handle(event)">



        </form>

</div>
Enter fullscreen mode Exit fullscreen mode

Leave the onsubmit part for later – that comes with the JS, which is Part #3.

Inside the form element add two input tags. The first creates the zip code input box, and the second creates the submit button, which activates the whole process, with the HTTP trigger function and the API.

<input type="text" name="zipcode" id="zipcode-input" accept="5" placeholder="Enter zip code">
<input size="100" type="submit" value="Get recommendations!" id="submit-button-style"></input>
Enter fullscreen mode Exit fullscreen mode

The rest of the code in this section formats the webpage. The code below would be placed inside the div with the id "container".

<div id="weather-result">

    <center>
    <h3>Weather Forecast for Tomorrow:</h3>
    </center>

</div>

  <br>
  <br>

<div id="recommendations-result">

    <center>
    <h3>Recommendations:</h3>
    </center>

</div>
Enter fullscreen mode Exit fullscreen mode

Now that we have the user interface complete, let's code the Azure function the user will trigger.

Part #2: Azure Functions

This part can get a little complicated because you’re dealing with a lot of things at the same time. I’m just going to cover the most important parts.

Create a Function App resource – once the resource is deployed, create a new HTTP trigger function. Don’t open the trigger yet, though, because you need to install an npm package in the console. Under Development Tools, open the console and install node-fetch. This makes calling the API a lot simpler.

Alt Text

Go back to your HTTP trigger and open the Code + Test tab. Create a const outside of the async function called fetch.

const fetch = require('node-fetch');
Enter fullscreen mode Exit fullscreen mode

This lets you use the npm package that was installed earlier.

We'll then define three constants: the first deals with the zip code, while the next one calls the API, and the final one formats the forecast data as a JSON file.

module.exports = async function (context, req) {
    context.log('JavaScript HTTP trigger function processed a request.');

    const zipcode = (req.query.zipcode || (req.body && req.body.zipcode));
    const apiResult = "";
    const jsonResult = await apiResult.json();

    context.res = {
        // status: 200, /* Defaults to 200 */
        body: jsonResult
    };
}
Enter fullscreen mode Exit fullscreen mode

Let's take a look at the apiResult constant a bit more closely because that's the most important one.

In your Open Weather account, go to the free 5 day, 3-hour forecast API documentation page here: https://openweathermap.org/forecast5#zip. Go to the “by ZIP code” section and copy the posted link. This link calls the 5 day, 3-hour forecast API.

Alt Text

api.openweathermap.org/data/2.5/forecast?zip={zip code},{country code}&appid={API key}
Enter fullscreen mode Exit fullscreen mode

Back in the HTTP trigger, let's modify our apiResult using this information, with await fetch () and the URL you just copied.

const apiResult = await fetch ("https://api.openweathermap.org/data/2.5/forecast?zip={zip code}");
Enter fullscreen mode Exit fullscreen mode

Then, let's make sure it's actually going to use the zip code entered when calling the API, by replacing the placeholder {zip code} with our variable zipcode:

const apiResult = await fetch ("https://api.openweathermap.org/data/2.5/forecast?zip=" + zipcode);
Enter fullscreen mode Exit fullscreen mode

Next, let's add a few parameters to limit the hours to a full day (i.e. cnt(or "count") as 8, for 8 3-hour segments) and use imperial units (instead of scientific ones, like Kelvin).

const apiResult = await fetch ("https://api.openweathermap.org/data/2.5/forecast?zip=" + zipcode + "&cnt=8&units=imperial");
Enter fullscreen mode Exit fullscreen mode

Finally, insert your Open Weather API key at the end, by tacking on &appid=, followed by your API key.

Part #3: The JavaScript

I’m not going to explain all of the JS either, but I am going to describe how to access certain information and call the trigger function.

async function handle(event) {
  event.preventDefault();

  var zipcode = document.getElementById("zipcode-input").value;
  console.log(zipcode);
  const resp = await fetch(
    "https://weatherapifunction.azurewebsites.net/api/WeatherAPI?zipcode=" +
      zipcode,
    {
      method: "POST",
    }
  );

  var data = await resp.json();
  console.log(data);

  const weatherForecastForTommorowNoon = data.list[6];
  const weatherForecastCity = data.city;

var output;

// Abbreviated algorithm
if(weatherForecastForTommorowNoon.pop >= .01){
  output = "string of rainy day activities";
} else if((weatherForecastForTommorowNoon.pop >= .01) && (weatherForecastForTommorowNoon.weather[0].description == "snow")){
  output = "string of snowy day activities";
}

  var weatherRegular = `
      <!Forecast data from API>
            `;

  var recommendations = `
      <p>${output}</p>

  `;

  $("#weather-result").html(weatherRegular);
  $("#recommendations-result").html(recommendations);
}
Enter fullscreen mode Exit fullscreen mode

The most important section of the code above is the resp constant. It calls the Azure trigger function using the trigger’s URL and sends the zip code entered on the website to the trigger function (by accessing the form element “zipcode-input” created earlier using document.getElementById).

async function handle(event) {
  event.preventDefault();

  var zipcode = document.getElementById("zipcode-input").value;
  console.log(zipcode);
  const resp = await fetch(
    "https://weatherapifunction.azurewebsites.net/api/WeatherAPI?zipcode=" +
      zipcode,
    {
      method: "POST",
    }
);
Enter fullscreen mode Exit fullscreen mode

Now, the entered zip code is run through the trigger function and used when the API is called. It uses POST rather than GET method, as the zip code is being sent to the Azure trigger function.

Notice console.log(data) – now that the data is logged in the console, we can access it using the next two constants. Const weatherForecastForTomorrowNoon accesses tomorrow's three-hour forecast data from 1 pm to 4 pm. The next constant accesses the city outputted in the console – it was only used in displaying the general forecast on the website, not in generating activity recommendations.

console.log(data);

const weatherForecastForTommorowNoon = data.list[6];
const weatherForecastCity = data.city;
Enter fullscreen mode Exit fullscreen mode

Next comes the algorithm – basically, create a list of activities, and then match weather to those activities (you need snow for sledding and skiing, sun and wind for sailing and flying a kite). Create if/else statements for these conditions and activities – if weatherForecastForTomorrowNoon.{enterWeatherConditionHere} is <, >, or = a certain temperature or measurement, make the variable output equal a string with the activities that are recommended based on the weather conditions.

// Abbreviated algorithm
if(weatherForecastForTommorowNoon.pop >= .01){
  output = "string of rainy day activities";
} else if((weatherForecastForTommorowNoon.pop >= .01) && (weatherForecastForTommorowNoon.weather[0].description == "snow")){
  output = "string of snowy day activities";
}
Enter fullscreen mode Exit fullscreen mode

After you have created all of these conditions (based on humidity, temperature, wind speed, and precipitation) create four solely weather-based if/else statements that cover all temperatures possible (but no other weather conditions). There may be a day without wind or precipitation, but there will always be temperature.

else if(weatherForecastForTommorowNoon.main.temp <= 30){
  output = "string of cold activities";
} else if((weatherForecastForTommorowNoon.main.temp >= 31 && weatherForecastForTommorowNoon.main.feels_like <= 60) && weatherForecastForTommorowNoon.pop == 0){
  output = "string of chilly day activities";
}

//Add more conditionals to the end
Enter fullscreen mode Exit fullscreen mode

Now there are no holes in the algorithm. Add these temperature-based statements to the end of your conditionals so that the forecast data is run through these last (because these are the most general statements, and conditionals should always be ordered with the most specific statement first and the most general statement last).

Final Result

Your project should now look something like this: https://github.com/TheDirector23/come-rain-or-shine

Alt Text

Of course, you can always add improvements! The recommendations could be customized based on user inputs (location, personality questions, preferred activities). The recommendations could also be linked to local businesses based on the entered zip code as well (a local marina might be linked to a recommendation to go sailing). Other locations and recommendations could be offered if the conditions aren't great.

That's about it! Hopefully now you're ahead of the weather when it comes to planning for tomorrow.

Discussion (0)