Overview
RestAction<T> is JDA’s interface for making asynchronous requests to the Discord API. It provides a fluent API for chaining operations, handling errors, and managing timeouts.
Most methods in JDA that interact with Discord return a RestAction that must be executed with queue(), submit(), or complete().
Execution Methods
queue()
Execute the request asynchronously with optional callbacks.
// Fire and forget
channel.sendMessage("Hello!").queue();
// With success callback
channel.sendMessage("Hello!").queue(message -> {
System.out.println("Sent: " + message.getId());
});
// With success and failure callbacks
channel.sendMessage("Hello!").queue(
message -> System.out.println("Success: " + message.getId()),
error -> System.err.println("Failed: " + error.getMessage())
);
submit()
Returns a CompletableFuture<T> for async/await patterns.
CompletableFuture<Message> future = channel.sendMessage("Hello!").submit();
future.thenAccept(message -> {
System.out.println("Sent: " + message.getId());
});
complete()
Blocking method! Use sparingly - blocks the current thread until the request completes.
Message message = channel.sendMessage("Hello!").complete();
System.out.println("Sent: " + message.getId());
map()
Transform the result to a different type.
RestAction<String> messageId = channel.sendMessage("Hello!")
.map(Message::getId);
messageId.queue(id -> System.out.println("ID: " + id));
flatMap()
Chain another RestAction on the result.
channel.sendMessage("Hello!")
.flatMap(message -> message.addReaction(Emoji.fromUnicode("👍")))
.queue();
onSuccess()
Run a callback without changing the return type.
channel.sendMessage("Hello!")
.onSuccess(message -> System.out.println("Sent!"))
.flatMap(message -> message.pin())
.queue();
Error Handling
onErrorMap()
Recover from errors by providing a fallback value.
RestAction<String> name = guild.retrieveMemberById(userId)
.map(Member::getEffectiveName)
.onErrorMap(error -> "Unknown User");
onErrorFlatMap()
Recover from errors with another RestAction.
channel.retrieveMessageById(messageId)
.onErrorFlatMap(error -> channel.sendMessage("Message not found"))
.queue();
mapToResult()
Convert the RestAction to a Result<T> that can be success or failure.
RestAction<Result<Message>> result = channel.retrieveMessageById(id)
.mapToResult();
result.queue(r -> {
if (r.isSuccess()) {
System.out.println("Found: " + r.get().getContentRaw());
} else {
System.out.println("Error: " + r.getFailure().getMessage());
}
});
Combining Actions
and()
Run two RestActions in parallel and combine their results.
RestAction<String> combined = guild.retrieveMemberById(id1)
.and(guild.retrieveMemberById(id2),
(member1, member2) -> member1.getEffectiveName() + " and " + member2.getEffectiveName()
);
allOf()
Run multiple RestActions in parallel.
List<RestAction<Message>> actions = Arrays.asList(
channel1.sendMessage("Hello!"),
channel2.sendMessage("Hi!"),
channel3.sendMessage("Hey!")
);
RestAction.allOf(actions).queue(messages -> {
System.out.println("Sent " + messages.size() + " messages");
});
zip()
Combine multiple RestActions into a list of results.
RestAction<List<Member>> members = RestAction.zip(
guild.retrieveMemberById(id1),
guild.retrieveMemberById(id2),
guild.retrieveMemberById(id3)
);
members.queue(list -> {
System.out.println("Retrieved " + list.size() + " members");
});
Delay Operations
delay()
Delay the next operation in the chain.
channel.sendMessage("This message will self-destruct in 10 seconds")
.delay(Duration.ofSeconds(10))
.flatMap(Message::delete)
.queue();
queueAfter()
Schedule the request to execute after a delay.
channel.sendMessage("Delayed message")
.queueAfter(5, TimeUnit.SECONDS);
Checks and Timeouts
setCheck()
Add a condition that must be true before the request executes.
BooleanSupplier condition = () -> System.currentTimeMillis() % 2 == 0;
channel.sendMessage("Lucky message")
.setCheck(condition)
.queue(
success -> System.out.println("Check passed!"),
error -> System.out.println("Check failed!")
);
timeout()
Set a maximum time the request can take.
channel.sendMessage("Fast message")
.timeout(5, TimeUnit.SECONDS)
.queue(
success -> System.out.println("Sent in time!"),
error -> System.out.println("Timeout!")
);
deadline()
Set an absolute timestamp deadline.
long deadline = System.currentTimeMillis() + 10000; // 10 seconds from now
channel.sendMessage("Message with deadline")
.deadline(deadline)
.queue();
Complete Example
Here’s a complete example showing multiple RestAction features:
public void sendWelcomeMessage(Guild guild, Member member) {
TextChannel channel = guild.getTextChannelById(welcomeChannelId);
if (channel == null) return;
// Create welcome embed
MessageEmbed embed = new EmbedBuilder()
.setTitle("Welcome!")
.setDescription("Welcome to " + guild.getName() + ", " + member.getAsMention())
.setColor(Color.GREEN)
.build();
// Send message, wait 30 seconds, then delete it
channel.sendMessageEmbeds(embed)
.flatMap(message -> message.addReaction(Emoji.fromUnicode("👋")))
.delay(Duration.ofSeconds(30))
.flatMap(message -> message.delete())
.queue(
success -> System.out.println("Welcome message sent and deleted"),
error -> System.err.println("Failed: " + error.getMessage())
);
}
Best Practices
Always call an execution method! A RestAction does nothing until you call queue(), submit(), or complete().
// ❌ This does nothing!
channel.sendMessage("Hello!");
// ✅ This actually sends the message
channel.sendMessage("Hello!").queue();
Prefer queue() over complete() - Async operations are faster and don’t block threads.
Don’t ignore rate limits - JDA handles them automatically with queue(), but complete(true) can bypass them and get your bot banned.
Related Pages