Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

JavaScript

Node.js forecast extra credit

I tried out the extra credit for node.js, where we were asked to create a console app using the forecast.io api. I got it to work, but wanted any feedback I could get to help clean up the code.

here is my forecast.js file

var forecast = require("./zipcodes");
var zip = process.argv.slice(2);
zip.forEach(forecast.getZip);

and here is my zipcodes.js

var http = require("http");
var https = require('https');

//Print out message
function printMessage(city, temp, soonSummary) {
  var message = "Current temp for " + city + " is " + temp + " degrees with "+ soonSummary;
  console.log(message);
}

//Print out error
function printError(error) {
  console.error(error.message);
}

function getZip(zip) {
  //Get zip
  var request = http.get("http://api.zippopotam.us/us/" + zip, function(res){
    var body = "";
    res.on('data', function (chunk) {
      body += chunk;
    });
    res.on('end', function() {
      if(res.statusCode === 200 ) {
        try {
          //Parse the data
          var zipCodeInfo = JSON.parse(body);
          //return the latitude and longitude
          var latitude = zipCodeInfo.places[0].latitude;
          var longitude = zipCodeInfo.places[0].longitude;
          var city = zipCodeInfo.places[0]["place name"];

          //Request info from forecast.io api
          var request = https.get("https://api.forecast.io/forecast/(api key)/" +  latitude + "," + longitude, function(res) {
            var body = "";
            //Read the data
            res.on('data', function (chunk) {
                body += chunk;
              });
            res.on('end', function() {
              if(res.statusCode === 200 ) {
                try {
                  //Parse the data
                  var weather = JSON.parse(body);
                  //Print the data
                  printMessage(city, weather.currently.temperature, weather.minutely["summary"]);
                } catch (error){
                  //Parse error
                  console.error("There was an error parsing the forecast data - " + error);
                }
              } else {
                //Status Code Error
                printError({message: "There was an error getting the forecast for " + username + "(" + http.STATUS_CODES[res.statusCode] + ")"});
              }
            });
          });
          //Connection error
          request.on('error', printError);

        } catch (error){
          //Parse error
          console.error("There was an error parsing the Zip Code data - " + error);
        }
      } else {
        //Status Code Error
        printError({message: "There was an error getting the Zip Code for " + zip + "(" + http.STATUS_CODES[res.statusCode] + ")"});
      }
    });
  });
  //connection error
  request.on('error', printError);
}

module.exports.getZip = getZip;

I have the api key in my personal file, but left it out here. You can insert yours where my parenthesis are, and it should work just fine.

4 Answers

Hi Steven,

This is really awesome, thanks for sharing. Because you asked for feedback, here is the program with changes I made. Basically, I broke the lower half of getZip into another function getForecast passing in a location object holding latitude, longitude and city.

var http = require("http");
var https = require("https");

// Print out message
function printMessage(city, temp, soonSummary) {
    var message = "Current temp for " + city + " is " + temp + " degrees with " + soonSummary;
    console.log(message);
}

// Print out error
function printError(error) {
    console.error(error.message);
}

function getForecast(location) {
    var url = "https://api.forecast.io/forecast/";
    var key = //(Your API key)
    url += key + "/" + location.latitude + "," + location.longitude;
    //Request info from forecast.io api
    var request = https.get(url, function(res) {
        var body = "";      
        //Read the data
        res.on('data', function (chunk) {
            body += chunk;
        });     
        res.on('end', function() {          
            if(res.statusCode === 200 ) {
                try {
                    //Parse the data
                    var weather = JSON.parse(body);
                    //Print the data
                    printMessage(location.city, weather.currently.temperature, weather.minutely["summary"]);
                } catch (error){
                    //Parse error
                    console.error("There was an error parsing the forecast data - " + error);
                }
            } else {
                //Status Code Error
                printError({message: "There was an error getting the forecast for " + username + " (" + http.STATUS_CODES[res.statusCode] + ")"});
            }
        });
        //Connection error
        request.on('error', printError);
    }); 
}

function getZip(zip) {
    //Get zip
    var request = http.get("http://api.zippopotam.us/us/" + zip, function(res) {
        var body = "";    
        res.on('data', function (chunk) {
            body += chunk;
        });
        res.on('error', function() {
            //Status Code Error
            printError({message: "There was an error getting the Zip Code for " +
            zip + " (" + http.STATUS_CODES[res.statusCode] + ")"});
        });    
        res.on('end', function(res) {
            try {
                //Parse the data
                var zipCodeInfo = JSON.parse(body);
                //return the latitude and longitude 
                var location = {};
                location.latitude = zipCodeInfo.places[0].latitude;
                location.longitude = zipCodeInfo.places[0].longitude;
                location.city = zipCodeInfo.places[0]["place name"];
            } catch(error) {
                //Parse error
                console.error("There was an error parsing the Zip Code data - " + error);
                return;
            }
            getForecast(location);
        });
    });  
    //connection error
    request.on('error', printError);
}
module.exports.getZip = getZip;

Robert,

Looks great! I was just about to start working on separating getZip into 2 functions. I originally had 2 functions, getZip and forecast, but was having problems getting the latitude, longitude, and city info into the forecast function. I was trying to return an object with the properties, but wasn't successful. Your way makes a lot of sense. Thanks for the feedback!

Andrew Chalkley
STAFF
Andrew Chalkley
Treehouse Guest Teacher

Awesome!

I notice you still have username :)

                printError({message: "There was an error getting the forecast for " + username + "(" + http.STATUS_CODES[res.statusCode] + ")"});

Also could you get away with the following with https?

  var request = http.get("http://api.zippopotam.us/us/" + zip, function(res){

Also try extracting the printer methods in another file and include them in to zipcodes.js.

You may want to extract this:

 //Request info from forecast.io api
          var request = https.get("https://api.forecast.io/forecast/(api key)/" +  latitude + "," + longitude, function(res) {
            var body = "";
            //Read the data
            res.on('data', function (chunk) {
                body += chunk;
              });
            res.on('end', function() {
              if(res.statusCode === 200 ) {
                try {
                  //Parse the data
                  var weather = JSON.parse(body);
                  //Print the data
                  printMessage(city, weather.currently.temperature, weather.minutely["summary"]);
                } catch (error){
                  //Parse error
                  console.error("There was an error parsing the forecast data - " + error);
                }
              } else {
                //Status Code Error
                printError({message: "There was an error getting the forecast for " + username + "(" + http.STATUS_CODES[res.statusCode] + ")"});
              }
            });

...in to it's own function like getForecast so it's not so nested.

Keep up the good work!

sure is a feel good moment when I make independent decisions that align with others - getForecast. Also, I just checked and https is supported for https.get("https://api.zippopotam.us/us/")

Andrew,

Thanks for the feedback! Https does work, so I will switch over to that. I will also go back over the getZip function to see how I can successfully split it up. I originally had two functions (getZip and forecast), but was having trouble returning an object holding the latitude and longitude info, and using it in the forecast function. I will keep working on it, and see what I come up with. Also, I really enjoyed the course. It was a great way to see a little of what node.js can do.

here's my answer:

forecast.js

var https = require('https');

// var API_KEY = "your key here";

function printForecast(summary,temperature){
    console.log("The forecast summary : " + summary + "\nTemperature : "+ temperature + "");
}

function printError(error){
    console.log(error.message);
}

// var latitude = 37.8267;
// var longitude = -122.423;

function get(latitude, longitude){

    var req = https.get("https://api.forecast.io/forecast/API_KEY/"+ latitude +","+ longitude +"", function(res){

        if(res.statusCode == 200){
            var body = "";
            res.on("data", function(chunk){
                body +=chunk;

            });
            res.on("end", function(){
                try{
                    var fc = JSON.parse(body);
                    printForecast(fc.currently.summary, fc.currently.temperature);
                }catch(e){
                    printError(e);
                }
            });

        }
    });
}
module.exports.get = get;


zipcode.js

var forecast = require('./forecast.js');

var http = require('http');


function printError(error){
    console.log(error.message);
}

// var zipcode = "85719";

function get(zipcode){

    var req = http.get("http://api.zippopotam.us/us/"+ zipcode +"", function(response){

        if(response.statusCode == 200){
            var body = "";
            response.on("data", function(chunk){
                body +=chunk;

            });
            response.on("end", function(){
                try{
                    var geo = JSON.parse(body);
                    forecast.get(geo.places[0].latitude, geo.places[0].longitude);
                }catch(e){
                    printError(e);
                }
            });
        }
    }); 
 } 

 module.exports.get = get;

app.js

var zipcode = require('./zipcode.js');

var zip = process.argv[2];

zipcode.get(zip);

Nice. Works like a charm

How do I get my unique API key? How do I know which sites provide such information?

Andrew Chalkley
Andrew Chalkley
Treehouse Guest Teacher

Forecast.io > Forecast.io API > Register