Search code examples
node.jsarraysjsonapiget

Requesting infromation from a API through Node.js


I hope you could please help me out, I'm running Node.js and trying to get a the city name from a API and it keeps showing an error saying it Cannot read property city_name of undefined.

It gets stuck on this line in the code:

const cityName = weatherData.data.city_name;

Any clue why its doing that? Please

// Creating the server of the weather app
const express = require('express');
const app = express();


const { StringDecoder } = require('string_decoder');
const decoder = new StringDecoder('utf8');

const https = require('https');


app.get('/', (req, res) => {
    const weatherPath = "https://api.weatherbit.io/v2.0/current?key=41c0f84d717a4764a26d144aa33a9443&city=melbourne,Australia"

    // Calling the weather app 
    https.get(weatherPath, (response) => {
        console.log(response.statusCode);
        
        // Getting the data from the weather app
        response.on('data', (d) => {
            //console.log(d);
            
            
            // Converting the buffer data from the weather app
            console.log(decoder.write(d));

            const weatherData = decoder.write(d);

            const cityName = weatherData.data.city_name;

            console.log(cityName);


          });
    });

    res.send("The server is up and running on the web");

});



app.listen(3000, () => 
{

    console.log('Server is running on port 3000');
});

Solution

  • Your data is a string and hence doesn't have those properties. You would need to JSON.parse it first.

    But there is another issue, your code will break as soon as more data is returned, because you listen only for a single chunk of data. You have to add up all chunks (add to the existing chunks on every data event) and process the full data on the end event.

    But in general the https.get method is very bare-bones, it will be a lot simpler to use a package like node-fetch:

    // Creating the server of the weather app
    const express = require('express');
    const app = express();
    
    const fetch = require('node-fetch')
    
    app.get('/', (req, res) => {
        const weatherPath = "https://api.weatherbit.io/v2.0/current?key=41c0f84d717a4764a26d144aa33a9443&city=melbourne,Australia"
    
        // Calling the weather app 
        fetch(weatherPath)
          .then(response => response.json())
          .then(weatherData => {
            // Getting the data from the weather app 
            const cityName = weatherData.data[0].city_name;
            console.log(cityName); 
          }).catch(e => {
            console.error('An error occured!', e);
          });
    
        res.send("The server is up and running on the web");
    });
    
    app.listen(3000, () => {
        console.log('Server is running on port 3000');
    });
    

    Additional information

    To address your comment:

    I converted the data into a string though in the command line it looked like a JSON.

    The term "JSON" is often used in a confusing way. Technically JSON (JavaScript Object Notation) is a serialization format, a string representation of an object or other basic JavaScript datatype (with limitations). The concept of a "live" object exists only in memory inside your script. So, the API is always sending you a string of characters. This string "is" JSON, i.e. uses JSON as method of representing structured data that, when parsed (!), can be turned back into a JavaScript object (in memory). So you are right that it looked like JSON since it is, but it's still a string at that point.

    It's like sending you a blueprint (2D representation - JSON string) of a house (3D object - the original object). (You obviously can't send a house in a letter so people are sending blueprints (JSON) instead.) It looks like a house, because it is representing one, but you can't yet open its door (access a property) or something. At that point it's still just something printed on a piece of paper (a string) that people recognize as a blueprint (it is valid JSON). You have to first build an actual house (parse the JSON back into an object) from the blueprint.

    (Of course this isn't made any better by using a variable name like json to represent the data parsed from JSON like it sometimes happens.)