Skip to content
Advertisement

Refactoring Embed message generation for Discord Bot

I am trying to refactor the code that I am using to generate embeds (user input makes an API call for info, which I display through the embed) with my bot in Discord. I have both a slash command and prefix command version of the code (so that people can either ask the bot with a prefix command or use the slash commands) and I am trying to pull the duplicated code for both those requests into a helper file.

The helper file: (/utils/itemHelper.js)

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

async function getItem( itemName ){
    if (itemName in itemAliases){ itemName = itemAliases[itemName] };
    const { body } = await request(ITEM_URL + encodeURIComponent(itemName));
    const { items } = await body.json();

    const [itemAnswer] = items;
    const itemEmbed = new MessageEmbed()
        .setTitle(itemAnswer.name)
        .setDescription('Mentor notes will go here.')
        .setImage(BASE_URL + itemAnswer.screenshot)
     
    console.log(itemEmbed);
}

module.exports = { getItem }

At this point, the console.log(itemEmbed) gives me what I want:

MessageEmbed {
  type: 'rich',
  title: 'Frost Brand',
  description: 'Mentor notes will go here.',
  url: null,
  color: null,
  timestamp: null,
  fields: [],
  thumbnail: null,
  image: { url: 'https://dom5api.illwiki.com/items/14/screenshot' },
  video: null,
  author: null,
  provider: null,
  footer: null
}

But by the time I call the function within the file were I create the slash command, I get an error message (which is discord telling me that the embed I want to send is lacking the description field):

data.embeds[0].description: This field is required.

The slash command file where I call the async function: (/commands/item.js)

const { SlashCommandBuilder } = require('@discordjs/builders');
const { MessageEmbed } = require('discord.js');
const { getItem } = require('../utils/itemHelper')

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

    async execute(interaction) {
        let itemName = interaction.options.getString('item_name');
        const itemEmbed = getItem( itemName );
        console.log(`itemEmbed:`+ itemEmbed);
        await interaction.reply({ embeds: [itemEmbed] });
    },
};

The console.log output is itemEmbed:[object Promise]

My hunch is that I am somehow misunderstanding/misapplying how async functions and promises work (and that the information I need is hidden somewhere inside [object Promise]). I have tried to do ‘return itemEmbed’ at the end of the helper file, but that didn’t solve the issue. I have also considered if I might be missing a param in my async function, but I don’t think I need another param, or if I did need one what role it would fill.

Thanks for any/all help in advance!

Answer

In your getItem function, there’s two problems:

  1. You made it async. When a function is asynchronous, it is considered as a Promise that you have to use the await keyword on await getItem(..) So that it will wait for the fetch to finish to finally continue executing your code.
  2. You don’t return anything on your function. You log the embed in your console. Try using it like so :
const { MessageEmbed } = require('discord.js');
const { request } = require('undici');
const { ITEM_URL, BASE_URL } = require('./utils');
const { itemAliases } =require('./itemAliases')

function getItem( itemName ){
    if (itemName in itemAliases){ itemName = itemAliases[itemName] };
    const { body } = await request(ITEM_URL + encodeURIComponent(itemName));
    const { items } = await body.json();

    const [itemAnswer] = items;
    const itemEmbed = new MessageEmbed()
        .setTitle(itemAnswer.name)
        .setDescription('Mentor notes will go here.')
        .setImage(BASE_URL + itemAnswer.screenshot)
    return itemEmbed
}

module.exports = { getItem }
        const itemEmbed = await getItem(itemName);
Advertisement