Define the slash command structure that Discord will display to users:
src/commands/example.rs
use serenity::builder::CreateCommand;pub fn register() -> CreateCommand { CreateCommand::new("example") .description("An example command")}
This creates a basic command with no options.
3
Implement run() Function
Add the command execution logic:
src/commands/example.rs
use serenity::{ all::{CommandInteraction, CreateInteractionResponse, CreateInteractionResponseMessage}, prelude::*,};use tracing::info;pub async fn run(ctx: &Context, interaction: &CommandInteraction) { info!("Received example command"); let message = CreateInteractionResponseMessage::new() .content("Hello from example command!"); let response = CreateInteractionResponse::Message(message); let _ = interaction.create_response(&ctx.http, response).await;}
4
Export in mod.rs
Add your new command to src/commands/mod.rs:
src/commands/mod.rs
pub mod anime;pub mod character;pub mod help;pub mod input_validation;pub mod manga;pub mod ping;pub mod recommend;pub mod register;pub mod response;pub mod search;pub mod songs;pub mod traits;pub mod unregister;pub mod whoami;pub mod example; // Add this line
5
Register in main.rs ready Event
Add your command to the registration list in src/main.rs at the ready event handler:
src/main.rs
async fn ready(&self, ctx: Context, ready: Ready) { let commands: Vec<CreateCommand> = vec![ commands::ping::register(), commands::help::register(), commands::songs::command::register(), commands::manga::command::register(), commands::anime::command::register(), commands::search::command::register(), commands::recommend::command::register(), commands::character::command::register(), commands::register::command::register(), commands::unregister::register(), commands::whoami::register(), commands::example::register(), // Add this line ]; let guild_commands = Command::set_global_commands(&ctx.http, commands).await; // ...}
See src/main.rs for the full implementation.
6
Add Match Arm in interaction_create
Route the command to your handler in src/main.rs at the interaction_create event:
External API clients use async reqwest::Client. Await those requests directly after deferring the Discord interaction:
use tracing::error;let result = match client .post("https://graphql.anilist.co/") .header("Content-Type", "application/json") .body(query_json.to_string()) .send() .await{ Ok(response) => Some(response), Err(error) => { error!(error = %error, "API request failed"); None }};
Use spawn_blocking only for synchronous work that can block the Tokio runtime, such as the current Redis cache helper calls.See src/utils/requests/anilist.rs for the AniList HTTP client and src/commands/recommend/command.rs for a bounded spawn_blocking cache example.