Skip to content

Component IDs

Daniel Tischner edited this page Nov 4, 2021 · 3 revisions

Overview

Component IDs are, among other things, used to carry information through an event.

For example the user who triggered a slash command or details to the query, which are then stored "inside" a button to retrieve the associated information back when it is clicked. By that, it can be implemented for example that a button can only be clicked by the original message author.

Component IDs in our system have to follow certain rules, which are explained in detail later.

Usage

Our API offers two options to work with component IDs.

SlashCommandAdapter

If your command happens to extend SlashCommandAdapter (our helper class), you can easily generate valid component IDs using the helper method generateComponentId. The method optionally accepts additional strings which can be used to carry information through the event.

For example, let us suppose you want to create a button that can only be clicked by the user who also triggered the command initially. Then you would create your buttons as such:

@Override
public void onSlashCommand(@NotNull SlashCommandEvent event) {
  event.reply("Do you want to continue?")
    .addActionRow(
      Button.of(ButtonStyle.SUCCESS, generateComponentId(event.getMember().getId()), "Yes"),
      Button.of(ButtonStyle.DANGER, generateComponentId(event.getMember().getId()), "No")
    .queue();
)

and then later, when retrieving the ButtonClickEvent, you get back the list of arguments:

@Override
public void onButtonClick(@NotNull ButtonClickEvent event, @NotNull List<String> args) {
  // Ignore if another user clicked the button
  String userId = args.get(0);
  if (!userId.equals(Objects.requireNonNull(event.getMember()).getId())) {
    event.reply("Sorry, but only the user who triggered the command can use these buttons.")
      .setEphemeral(true)
      .queue();
    return;
  }

  event.reply("Nice!").queue();
}

SlashCommand

Alternatively, commands can also implement the interface SlashCommand directly, instead of using the helper class SlashCommandAdapter. In that case, in order to use component IDs, one has to do some basic setup first.

Component IDs can be generated by using a ComponentIdGenerator, which the command system will provide to the command by calling the acceptComponentIdGenerator method, that each command has to implement, once during setup.

So as first step, you have to memorize this generator:

public final class MyCommand implements SlashCommand {
    private ComponentIdGenerator componentIdGenerator;

    ...

    @Override
    public void acceptComponentIdGenerator(@NotNull ComponentIdGenerator generator) {
        componentIdGenerator = generator;
    }
}

After that is done, component IDs can be generated easily as well, for example:

componentIdGenerator.generate(new ComponentId(getName(), ...), Lifespan.REGULAR);

where ... are the optional arguments you want to pass.

The previous button example would now look like:

@Override
public void onSlashCommand(@NotNull SlashCommandEvent event) {
  event.reply("Do you want to continue?")
    .addActionRow(
      Button.of(
        ButtonStyle.SUCCESS,
        componentIdGenerator.generate(
          new ComponentId(getName(), Arrays.asList(event.getMember().getId()),
          Lifespan.REGULAR),
        "Yes"),
      Button.of(
        ButtonStyle.DANGER,
        componentIdGenerator.generate(
          new ComponentId(getName(), Arrays.asList(event.getMember().getId()),
          Lifespan.REGULAR),
        "No")
    .queue();
)

Lifespan

Component IDs can have different lifespans. If a component ID has expired, associated events can not be used anymore. For example, a button can not be clicked anymore.

The default lifespan to use is Lifespan.REGULAR. IDs associated with this lifespan will generally be valid long enough for most use cases (multiple days). However, in some cases it might be necessary to create IDs that will not expire. Lifespan.PERMANENT can be used for that, but do not overuse it.

Note that the lifetime of a component ID is refreshed each time it is used. Hence, IDs only expire if they have not been used by anyone for a long time.

Details

Technically, for JDA, component IDs could be any text, as long as it is:

  • unique among other components in the event
  • not longer than 100 characters

To overcome those limitations and ease the workflow for users, our API generates component IDs as UUIDs (which are unique by default).

In order to attach arbitrary information (that also might be longer than just 100 characters) to the component ID, we store the actual information (the payload) externally in a database instead of stuffing it into the component ID itself. So while the actual component ID is just a UUID, we associate it to the corresponding information in a database.

See Component ID Store for more details on the underlying system and the implementation.

Clone this wiki locally