The AerisWeather Javascript SDK can solve weather-based problems all while steering clear of the troublesome tasks that go into styling a web page. This can be done using the SDK’s module which can be installed from the Yarn or NPM ecosystem. This tutorial will outline the steps required to use the JavaScript SDK’s NPM module and build a Travel Buddy along the way.
Travel Buddy will help users understand what temperatures to expect during their next trip. By passing the location and date of travel, the application will query our API and provide some pertinent details that will prepare the user for mother nature. The expected output will look something like this:
Here’s what your Travel Buddy expects in Phoenix:
Average High: 71°F
Average Low: 48°F
Extreme High: 79°F
Extreme Low: 38°F
Before getting started, there are some steps to take that will ensure a successful tutorial:
To setup the project and begin using the SDK, follow the steps below:
Now that we can access the SDK’s features with the aeris variable, let’s build our request for weather data. You can add various parameters to your API query by chaining methods to the aeris.api() method like so:
1 2 3 4 5 6 7 8 9 10 |
aeris .api() .endpoint('observations/summary') .place(destination) .from(dateRangeObject.fromDate.toLocaleDateString()) .to('+30days') .plimit(30) .limit(5) .fields('id,loc.place,periods.summary.dateTimeISO,periods.summary.temp') .get() |
The first 2 methods include the endpoint and location where the destination variable comes from the user input. The argument being passed to the from parameter is 15 days prior to the input date. Our to date is going to take a relative offset, +30days, which is relative to the from value. The plimit() method will take an integer to override the default number of periods (or days in this case) that will be returned. Listing out a limit() applies to the number of stations returned which allows the application to iterate over multiple stations. Lastly, the fields() method will reduce the output to only include the values needed. So far each of these methods represent a section of the API query via parameters, endpoint, or action. This translates into a query that would look like this:
1 |
https://api.aerisapi.com/observations/summary/[LOCATION]?from=[FROM_DATE]&to=+30days&plimit=30&limit=5&fields=id,loc.place,periods.summary.dateTimeISO,periods.summary.temp&client_id=[CLIENT_ID]&client_secret=[CLIENT_SECRET] |
Next, the get() method is used which will do precisely that, get the data. The response is conveniently stored in a Promise object which allows us to wait for the response before we evaluate the data further.
Once the data is ready for processing the result will be used to determine which station to use. This criteria is based on number of days returned in the summary which should be 30:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
.then(result => { const stations = result.data; return new Promise((resolve, reject) => { stations.forEach(station => { if (station.periods.length === 30) { resolve(station); } else { reject('Unable to find station with 30 days of data.') } }); }); }) |
You’ll notice we are returning a Promise here as we will need to give the application time to iterate over the stations before we can move forward. Once the station has been selected, we can get ready to log the necessary weather data. In the next section we are formatting the location name, returning temperature data, and logging our results:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
.then(station => { let cityNameArr = destination.split(",")[0].split(" "); let formattedName = []; cityNameArr.forEach(word => { formattedName.push(word.charAt(0).toUpperCase() + word.substring(1)); }); const tempData = generateTemps(station); const extremes = tempData.extremes(); const average = tempData.avg(); console.log(<pre class="inline:true decode:1 " >Here's what your Travel Buddy expects in ${formattedName.join(" ")}:\n |
);
console.log(
Average High: ${average.high}°F);
console.log(
Average Low: ${average.low}°F\n);
console.log(
Extreme High: ${extremes.high}°F);
console.log(
Extreme Low: ${extremes.low}°F);
})
The generateTemps() will return an object that contains an array of the highs and lows as well as a methods to help evaluate these metrics. These methods will identify averages as well as the min and max values:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
function generateTemps(station) { const periods = station.periods; let temps = {}; temps.highs = periods.map(period => period.summary.temp.maxF); temps.lows = periods.map(period => period.summary.temp.minF); temps.avg = function() { let average = {}; let highSum = 0; let lowSum = 0; for (let i = 0; i < this.highs.length; i++) { highSum += this.highs[i]; } for (let i = 0; i < this.lows.length; i++) { lowSum += this.lows[i]; } average.high = Math.round(highSum / this.highs.length); average.low = Math.round(lowSum / this.lows.length); return average; }; temps.extremes = function() { let extremes = {}; extremes.high = Math.max(...this.highs); extremes.low = Math.min(...this.lows); return extremes; }; return temps; } |
Our date was also converted into last year minus 15 days which was accomplished with the following snippet:
1 2 3 4 5 6 7 8 9 10 |
function generateDateRange(travelDate) { let dates = {}; const today = new Date(); dates.travelDate = new Date(travelDate); const lastYear = new Date(dates.travelDate.setFullYear(today.getFullYear() - 1)); dates.fromDate = new Date(lastYear.setDate(lastYear.getDate() - 15)); return dates; } |
The last bit of code will handle the arguments passed the script (location and date). Additionally, we have logic to ensure both of these values were sent and warning the user in case they were not included:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
const arguments = process.argv.slice(2); const destination = arguments[0]; const travelDate = arguments[1]; if (destination === undefined) { console.error('Missing destination. Try using "node app.js '[destination]' [MM/DD/YYYY]".'); return; } if (travelDate === undefined) { console.error('Missing travel date. Try using "node app.js '[destination]' [MM/DD/YYYY]".'); return; } if (arguments.length > 2) { console.error(<pre class="inline:true decode:1 " >Too many arguments -> ${arguments.join("|")}. Try using "node app.js "[destination]" [MM/DD/YYYY]". |
);
return;
}
Putting all those pieces together will look something like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
const AerisWeather = require('@aerisweather/javascript-sdk'); const aeris = new AerisWeather('CLIENT_ID', 'CLIENT_SECRET'); const arguments = process.argv.slice(2); const destination = arguments[0]; const travelDate = arguments[1]; if (destination === undefined) { console.error('Missing destination. Try using "node app.js [destination] [MM/DD/YYYY]".'); return; } if (travelDate === undefined) { console.error('Missing travel date. Try using "node app.js [destination] [MM/DD/YYYY]".'); return; } if (arguments.length > 2) { console.error(<pre class="inline:true decode:1 " >Too many arguments -> ${arguments.join("|")}. Try using "node app.js "[destination]" [MM/DD/YYYY]". |
);
return;
}
const dateRangeObject = generateDateRange(travelDate);
aeris
.api()
// building the query
.endpoint(‘observations/summary’)
.place(destination)
.from(dateRangeObject.fromDate.toLocaleDateString())
.to(‘+30days’)
.limit(5)
.plimit(30)
.fields(‘id,loc.place,periods.summary.dateTimeISO,periods.summary.temp’)
// now get the results
.get()
.then(result => {
const stations = result.data;
return new Promise((resolve, reject) => {
stations.forEach(station => {
if (station.periods.length === 30) {
resolve(station);
} else {
reject(‘Unable to find station with 30 days of data.’)
}
});
});
})
.then(station => {
let cityNameArr = destination.split(“,”)[0].split(” “);
let formattedName = [];
cityNameArr.forEach(word => {
formattedName.push(word.charAt(0).toUpperCase() + word.substring(1));
});
const tempData = generateTemps(station);
const extremes = tempData.extremes();
const average = tempData.avg();
console.log(
Here's what your Travel Buddy expects in ${formattedName.join(" ")}:\n);
console.log(
Average High: ${average.high}°F);
console.log(
Average Low: ${average.low}°F\n);
console.log(
Extreme High: ${extremes.high}°F);
console.log(
Extreme Low: ${extremes.low}°F);
})
.catch(error => {
console.error(error);
});
function generateDateRange(travelDate) {
let dates = {};
const today = new Date();
dates.travelDate = new Date(travelDate);
const lastYear = new Date(dates.travelDate.setFullYear(today.getFullYear() – 1));
dates.fromDate = new Date(lastYear.setDate(lastYear.getDate() – 15));
return dates;
}
function generateTemps(station) {
const periods = station.periods;
let temps = {};
temps.highs = periods.map(period => period.summary.temp.maxF);
temps.lows = periods.map(period => period.summary.temp.minF);
temps.avg = function() {
let average = {};
let highSum = 0;
let lowSum = 0;
for (let i = 0; i < this.highs.length; i++) {
highSum += this.highs[i];
}
for (let i = 0; i < this.lows.length; i++) {
lowSum += this.lows[i];
}
average.high = Math.round(highSum / this.highs.length);
average.low = Math.round(lowSum / this.lows.length);
return average;
};
temps.extremes = function() {
let extremes = {};
extremes.high = Math.max(…this.highs);
extremes.low = Math.min(…this.lows);
return extremes;
};
return temps;
}
Once all the code is in place you will be able to run the application from the root of the project with a simple command node app.js "[DESTINATION]" [MM/DD/YYYY]. The destination variable needs to be in quotes in case your location has a space in the name as the script is ready to handle that. Additionally, the date will need to be the format mentioned above as this is a format the API expects.
Now that you’re well equipped with the tools and steps needed to use the NPM module, install the package today and build the next best weather app!
Not an AerisWeather customer? Sign up for a free trial of the Weather Data API and AMP, the Aeris Mapping Platform.
No comments yet.
Be the first to respond to this article.