logo

Constatic

Discord Bot BaseResponders

Params

Transform custom id of components into http routes

What are CustomID params?

Let's go a little beyond the conventional, on this base a resource present in several API server tools was implemented to allow more advanced systems to be developed more easily.

Just like in http routes, we can pass parameters to the customIds of buttons, select menus and modals. See how simple it is:

First let's create a user context command:

src/discord/commands/context/manage.ts
 
createCommand({
    name: "Manage",
    type: ApplicationCommandType.User,
    async run(interaction){
        const { targetUser } = interaction;
 
        const embed = new EmbedBuilder({ description: `Manage ${targetUser}` });
        const row = createRow(
            new ButtonBuilder({ 
                customId: `manage/user/${targetUser.id}/kick`, 
                label: "Kick", style: ButtonStyle.Secondary 
            }),
            new ButtonBuilder({ 
                customId: `manage/user/${targetUser.id}/ban`, 
                label: "Ban", style: ButtonStyle.Danger 
            }),
            new ButtonBuilder({ 
                customId: `manage/user/${targetUser.id}/timeout`, 
                label: "Timeout", style: ButtonStyle.Danger 
            }),
            new ButtonBuilder({ 
                customId: `manage/user/${targetUser.id}/alert`, 
                label: "Alert", style: ButtonStyle.Primary 
            })
        );
 
        interaction.reply({ flags: ["Ephemeral"], embeds: [embed], components: [row] });
    }
});

With this we can create a Responder that expects any button component that follows this pattern in the customId.

It should start with manage/user and then have two more parameter segments separated by / and starting with :, where the first will be the user id and the second will be an action.

It would look like this: manage/user/:userId/:action

So we can define this pattern and any button where the customId follows it, will be responded by the defined function. You can get the parameters in the second argument of the function.

src/discord/responders/manage.ts
// Dynamic button component function
createResponder({
    customId: "manage/user/:userId/:action",
    types: [ComponentType.Button], cache: "cached",
    async run(interaction, params) {
        const { action, userId } = params;
        const targetMember = await interaction.guild.members.fetch(userId);
 
        switch(action){
            case "kick": {
                targetMember.kick();
                // do things ...
                break;
            }
            case "ban": {
                targetMember.ban();
                // do things ...
                break;
            }
            case "timeout": {
                targetMember.timeout(60000);
                // do things ...
                break;
            }
            case "alert": {
                targetMember.send({ /* ... */ });
                // do things ...
                break;
            }
        }
    },
});

You can use this feature with any type of Responder, but don't forget that discord has a 100 character limit on customIds.

Transforming CustomID parameters

The createResponder function has an option where you can specify a way to transform the parameters object, which initially has both keys and values that are just strings. Check it out:

Transform the value parameter into a number, so you can use numeric functions

Botão
new Button({
    customId: `count/1`,
    label: "Count", 
    style: ButtonStyle.Primary 
})
Responder
createResponder({
    customId: "count/:value", cache: "cached",
    types: [ComponentType.Button],
    parse: params => ({ 
        value: Number(params.value) 
    }), 
    async run(interaction, { value }) {
        console.log(value + 1); // 2
        console.log(value.toFixed(2)); // "1.00"
    }
});

Wildcards

You can also use wildcards if you want to respond to routes with more or less segments.

Use ** to represent any pattern of segments after the / (slash)

CustomIds that will be responded to
- "giveway"
- "giveway/users"
- "giveway/gifts/nitro"
- "giveway/gifts/account/creator/expiresAt"
Responder
createResponder({
    customId: "giveway/**", cache: "cached",
    types: [ComponentType.Button],
    async run(interaction, { _ }) {
        // giveway _: ""
        // giveway/users _: "users"
        // giveway/gifts/nitro _:"gifts/nitro"
        // giveway/gifts/account/creator/expiresAt _:"gifts/account/creator/expiresAt"
    }
});

The examples on this page were all with buttons, but this feature can be used with any type of responder!

On this page