Search code examples
javascriptnode.jsdiscord.js

Passing multiple Embeds through a helper function for Discord Bot


I have refactored my code to remove some redundancy, part of which was making helper functions for the generation of embeds that my bot sends as a reply. For one of the slash commands, the bot is supposed to send back multiple embeds.

mercHelper.js (Houses the helper function inside the utils folder)

const { MessageEmbed } = require('discord.js');
const { request } = require('undici');
const { MERC_URL, BASE_URL } = require('./utils');
const { mercAliases } =require('./mercAliases')

async function getMerc( mercName ){
    if (mercName in mercAliases){ mercName = mercAliases[mercName] };
    const { body } = await request(MERC_URL + encodeURIComponent(mercName));
    const { mercs } = await body.json();

    const [mercAnswer] = mercs;
    const mercEmbed = new MessageEmbed()
        .setTitle(mercAnswer.name)
        .setDescription('Mentor notes will go here.')
        .setImage(BASE_URL + mercAnswer.screenshot)
    const mercLeaderEmbed = new MessageEmbed()
        .setImage(BASE_URL+'/commanders/'+ mercAnswer.commander_id+'/screenshot')
        .setDescription('Name of mercenary group leader: '+ mercAnswer.bossname)
    const mercTroopEmbed = new MessageEmbed()
        .setImage(BASE_URL+'/commanders/'+ mercAnswer.unit_id+'/screenshot')
        .setDescription('Number of units: '+ mercAnswer.nrunits)
    return [mercEmbed, mercLeaderEmbed, mercTroopEmbed];
    
}

module.exports = { getMerc }

merc.js (slash command file)

const { SlashCommandBuilder } = require('@discordjs/builders');
const { getMerc } = require('../utils/mercHelper');


module.exports = {
    data: new SlashCommandBuilder()
        .setName('merc')
        .setDescription('Replies with information about a merc')
        .addStringOption(option => option.setName('merc_name').setDescription('Enter the name of the mercenary').setRequired(true)),

    async execute(interaction) {
        let mercName = interaction.options.getString('merc_name');
        const mercEmbed = await getMerc( mercName );
        const mercLeaderEmbed = await getMerc( mercName );
        console.log('mercLeaderEmbed'+mercLeaderEmbed)
        const mercTroopEmbed = await getMerc( mercName );
        console.log('mercTroopEmbed'+mercTroopEmbed)
        await interaction.reply({ embeds: [mercEmbed, mercLeaderEmbed, mercTroopEmbed] });
    },
};

When I run the code I have currently, I get the following error message: DiscordAPIError: Invalid Form Body and then empty data.embeds.

I assume this is happening because when I 'return' embeds from the helper function, it is now going through somehow. I added console.logs to the helper file - all the information was present.

When I tried to do the same in the slash command file (merc.js), I get mercLeaderEmbed[object Object],[object Object],[object Object] and the same for the second console.log.

Maybe the return is working properly, but I am not calling the information correctly, which is resulting in the return of [object Object], but I am not sure on how to solve that issue/how to rewrite the code to avoid this.


Solution

  • You're calling await getMerc(mercName) three times and assign the same value to three different variables (mercEmbed, mercLeaderEmbed, and mercTroopEmbed). If you return an array of the three embeds ([mercEmbed, mercLeaderEmbed, mercTroopEmbed]) from getMerc, you don't need to call it more than once.

    When you log 'mercLeaderEmbed'+mercLeaderEmbed, you receive mercLeaderEmbed[object Object],[object Object],[object Object] because mercLeaderEmbed is already an array of the three objects (and they get stringified because you concatenate the array with a string).

    I think what you want is either destructuring the returned array like this:

    async execute(interaction) {
      let mercName = interaction.options.getString('merc_name');
      let [mercEmbed, mercLeaderEmbed, mercTroopEmbed] = await getMerc(mercName);
    
      await interaction.reply({
        embeds: [mercEmbed, mercLeaderEmbed, mercTroopEmbed],
      });
    }
    

    Or just sending the returned array of embeds like this:

    async execute(interaction) {
      let mercName = interaction.options.getString('merc_name');
      let embeds = await getMerc(mercName);
    
      await interaction.reply({ embeds });
    }