Discord.js crypto currency command returning undefined for prices

I created a command to get the price data of a given cryptocurrency. When I run my command, the embed has “undefined” for each price value.

Here is my code:

module.exports = {
    name: 'crypto',
    description: 'gets crypto data',
    async execute (message, args) {

        let cc = args.slice(0).join(' ');

        const noArgs = new Discord.MessageEmbed()
        .setTitle('Missing arguments')
        .setColor((Math.random() * 0xFFFFFF << 0).toString(16).padStart(6, '0'))
        .setDescription('You are missing some args (ex: -crypto bitcoin || -covid dogecoin)')
        .setTimestamp(new Date().getTime())
    
        if(!cc) return message.channel.send(noArgs);

        await fetch(`https://api.coingecko.com/api/v3/simple/price?ids=${cc}&vs_currencies=usd%2Ceur%2Cgbp`)
        .then (response => response.json)
        .then(data => {
            let usdprice = data.usd
            let europrice = data.eur
            let gbpprice = data.gbp

            const embed = new Discord.MessageEmbed()
            .setTitle(`**Current price of ${cc}:**`)
            .setDescription('This data might be inaccurate.')
            .setColor((Math.random() * 0xFFFFFF << 0).toString(16).padStart(6, '0'))
            .setTimestamp(new Date().getTime())
            .addField('**USD:**', usdprice, true)
            .addField('**EURO:**', europrice, true)
            .addField('**GBP:**', gbpprice, true)

            message.channel.send(embed)
        })
        
    }
}

There is also no error in the console when I run the command.

Answer

You can use async/await if you’ve already got an async execute function. this way you can get rid of the then()s.

One of the problem is what @Mellet mentioned, you need to call response.json().

The other one is that the fetch data looks like this (if the coin id is “bitcoin”):

{
  "bitcoin": {
    "usd": 44833,
    "eur": 36948,
    "gbp": 32383
  }
}

It means that it returns an object which contains another object with the coin id as the key. So if cc‘s value is bitcoin, you can get the USD price from data.bitcoin.usd. You can’t and don’t want to hardcode the coin id though, so you will need to add the key as a variable: data[coinId].usd.

I also added a helper function to check if the returned data is empty, so you can send an error message:

const isEmptyObject = (obj) => Object.keys(obj).length === 0;

module.exports = {
  name: 'crypto',
  description: 'gets crypto data',
  async execute(message, args) {
    let cc = args.slice(0).join(' ');

    if (!cc) {
      const noArgs = new Discord.MessageEmbed()
        .setTitle('Missing arguments')
        .setColor('RANDOM')
        .setDescription(
          'You are missing some args (ex: -crypto bitcoin || -covid dogecoin)',
        )
        .setTimestamp(new Date().getTime());

      return message.channel.send(noArgs);
    }

    const response = await fetch(
      `https://api.coingecko.com/api/v3/simple/price?ids=${cc}&vs_currencies=usd%2Ceur%2Cgbp`
    );
    const data = await response.json();

    if (isEmptyObject(data)) {
      return message.channel.send(
        `No returned data from the API. Are you sure "${cc}" is a valid id?`,
      );
    }

    let usdprice = data[cc].usd;
    let europrice = data[cc].eur;
    let gbpprice = data[cc].gbp;

    const embed = new Discord.MessageEmbed()
      .setTitle(`**Current price of ${cc}:**`)
      .setDescription('This data might be inaccurate.')
      .setColor('RANDOM')
      .setTimestamp(new Date().getTime())
      .addField('**USD:**', usdprice, true)
      .addField('**EURO:**', europrice, true)
      .addField('**GBP:**', gbpprice, true);

    message.channel.send(embed);
  },
};

PS: You can set the colour to 'RANDOM', so you don’t need to use extra functions.

enter image description here

Leave a Reply

Your email address will not be published. Required fields are marked *