CodingTrain / Discord-Bot-Examples

Bot Examples for Fall 2023
20 stars 7 forks source link

Propose using discord api for deploying commands #7

Closed dipamsen closed 1 year ago

dipamsen commented 1 year ago

Discord.JS

// ...  stuff to get all the commands using djs ... //

// Construct and prepare an insance of the REST module
const rest = new REST().setToken(process.env.TOKEN);

// and deploy your commands!
(async () => {
  try {
    console.log(`Started refreshing ${commands.length} application (/) commands.`);

    // The put method is used to fully refresh all commands in the guild with the current set
    const data = await rest.put(Routes.applicationGuildCommands(process.env.CLIENTID, process.env.SERVERID), {
      body: commands,
    });

    console.log(`Successfully reloaded ${data.length} application (/) commands.`);
  } catch (error) {
    // And of course, make sure you catch and log any errors!
    console.error(error);
  }
})();

Discord API

// ...  stuff to get all the commands using djs ... //

// Deploy your commands!
(async () => {
  try {
    console.log(`Started refreshing ${commands.length} application (/) commands.`);

    // make a PUT request, with the commands as the body
    const url = `https://discord.com/api/applications/${process.env.CLIENTID}/commands`
    const res = await fetch(url, {
      method: "PUT", 
      headers: {
        "Content-Type": "application/json",
        Authorization: "Bot " + process.env.TOKEN
      }, 
      body: JSON.stringify(commands)
    })
    const data = await res.json()

    console.log(`Successfully reloaded ${data.length} application (/) commands.`);
  } catch (error) {
    // And of course, make sure you catch and log any errors!
    console.error(error);
  }
})();
shiffman commented 1 year ago

Intersting, I will think about this @dipamsen! The reason I think I might prefer to keep it the other way is just to be able to mirror the discord.js guide. What's the main advantage of using DIscord API directly would you say?

dipamsen commented 1 year ago

Nothing, really. I just don't like the guide method because the REST module is actually discord js's internal library wrapper to make requests to the api. It is in fact undocumented in the main documentation, and there isn't any front-facing interface/function to perform the deployment process (unlike other things). If all we want to do is to make a http request, I think we should just make the request ourselves (since Djs doesn't have a wrapper around it), instead of messing with undocumented api just for making a request. I also think that the fetch version might be easier to understand for some people and also applicable in more scenarios.

Though, I agree that if you'd like to be consistent with the guide, you should just use it. (After all, this is just repetitive code anyway, someone might as well just copy paste this code every time, and they won't need to change anything about it)

Edit: After further research, it looks like Djs is now recommending this (REST) method, so there shouldn't be any problem using it.

dipamsen commented 1 year ago

I asked in the Discord.js discord, why there isnt an abstraction on top of this for registering slash commands. This is what I found:

There is, in fact a class ApplicationCommandManager, which allows us to write code like this:

// Set all global commands
client.application.commands.set([
  {
    name: 'test',
    description: 'A test command',
  },
])
  .then(console.log)
  .catch(console.error);

// Remove all guild commands
guild.commands.set([])
  .then(console.log)
  .catch(console.error);

The problem lies in what context we are using Discord.JS. The normal usecase for this library is for a long-running process, (a Discord bot waiting for commands to execute), for which it connects via Websockets to the Discord API. This is a persistent connection, and all commands we run (sendMessage(), reply(), react(), ...) are sent through the websocket (not HTTP requests). Similarly, Discord sends all the events and responses (interactionCreate, messageCreate, ...) through the websocket. So, naturally the core functionality of Discord.JS is based on sending and receiving messages through Websockets.

It just so happens, that registering slash commands is a standalone job, and doesn't require a long running process, i.e. websockets unlike other tasks. For this, we only need to make an HTTP request. The ApplicationCommandManager class uses the websocket connection to actually register the slash commands, under the usual client login-event flow. (It is still possible to do this in a standalone script - create client and set commands, but it becomes overkill to use a websocket since this is doable just with a single http request. The actual usecase for the above class is to dynamically register commands, when the bot is running, eg. in response to another command.) This is why we need to access the low level REST module to make requests to the API.

I think it is fine to use this, maybe this additional info can be helpful to understand why the syntax is weirder as compared to the other stuff.

dipamsen commented 1 year ago

Closing as corresponding video is already recorded using Djs syntax