| Crates.io | rs-hook |
| lib.rs | rs-hook |
| version | 1.0.0 |
| created_at | 2025-12-28 18:25:51.010766+00 |
| updated_at | 2025-12-28 18:25:51.010766+00 |
| description | A lightweight, production-ready Discord webhook library |
| homepage | |
| repository | |
| max_upload_size | |
| id | 2009244 |
| size | 142,257 |
A lightweight Discord webhook library for Rust built on hyper.
New to Rust or webhooks? Start with the Getting Started Guide 🚀
(mostly) vibecoded by GLM 4.7 on opencode as a test, this will eventually improve as I need it to.
Add this to your Cargo.toml:
[dependencies]
rs-hook = "0.1"
ps. use .env
use rs_hook::{MessageBuilder, Webhook};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let webhook = Webhook::new("https://discord.com/api/webhooks/...")?;
let message = MessageBuilder::new()
.content("Hello, Discord!")
.username("My Bot")
.build()?;
webhook.send(message).await?;
Ok(())
}
use rs_hook::{Embed, MessageBuilder, Webhook};
let embed = Embed {
title: Some("Title".to_string()),
description: Some("Description".to_string()),
color: Some(0x5865F2),
..Default::default()
};
let message = MessageBuilder::new()
.content("Check this out!")
.embed(embed)
.build()?;
webhook.send(message).await?;
use rs_hook::{Embed, EmbedAuthor, EmbedField, EmbedFooter, MessageBuilder};
let embed = Embed {
title: Some("Rich Embed".to_string()),
author: Some(EmbedAuthor {
name: "Author".to_string(),
url: Some("https://example.com".to_string()),
icon_url: Some("https://...".to_string()),
..Default::default()
}),
fields: vec![
EmbedField {
name: "Field 1".to_string(),
value: "Value 1".to_string(),
inline: true,
},
EmbedField {
name: "Field 2".to_string()),
value: "Value 2".to_string(),
inline: true,
},
],
footer: Some(EmbedFooter {
text: "Footer".to_string(),
..Default::default()
}),
..Default::default()
};
use rs_hook::{Attachment, MessageBuilder, Webhook};
use std::path::PathBuf;
let message = MessageBuilder::new()
.content("Here's a file!")
.build()?;
let attachment = Attachment {
path: PathBuf::from("file.txt"),
description: Some("A text file".to_string()),
};
webhook.send_with_attachments(message, vec![attachment]).await?;
use rs_hook::{Embed, MessageBuilder};
let embed1 = Embed {
title: Some("First".to_string()),
color: Some(0x5865F2),
..Default::default()
};
let embed2 = Embed {
title: Some("Second".to_string()),
color: Some(0x57F287),
..Default::default()
};
let message = MessageBuilder::new()
.embeds(vec![embed1, embed2])
.build()?;
The main client for sending webhooks.
let webhook = Webhook::new(url)?;
let webhook = Webhook::new(url)?.with_timeout(30); // 30 second timeout
webhook.send(message).await?;
webhook.send_with_attachments(message, attachments).await?;
Builder for Discord webhook messages.
MessageBuilder::new()
.content("Message content")
.username("Override username")
.avatar_url("https://...")
.tts(true)
.embed(embed)
.embeds(vec![embed1, embed2])
.allow_mention(AllowedMention::Users)
.build()?
Discord rich embed structure.
Embed {
title: Some("Title".to_string()),
description: Some("Description".to_string()),
url: Some("https://...".to_string()),
color: Some(0x00FF00),
timestamp: Some("2024-01-01T00:00:00Z".to_string()),
footer: Some(EmbedFooter { ... }),
image: Some(EmbedMedia { ... }),
thumbnail: Some(EmbedMedia { ... }),
author: Some(EmbedAuthor { ... }),
fields: vec![EmbedField { ... }],
..Default::default()
}
The library uses a custom WebhookError type:
use rs_hook::{WebhookError, Result};
async fn send_webhook() -> Result<()> {
webhook.send(message).await?;
Ok(())
}