Why create this module?
There are lot of modules available for making discord webhook calls from Roblox but often they disregard the API limits for message lengths and request limits which lead to failed or dropped messages.
It was only recently that changes to the HTTPService allowed developers to have more control over how HTTP calls are made. The addition of RequestAsync now allows us to make more informed decisions based upon the API state.
Main features
Request throttling - Using the header data rate limits are handled accordingly.
Message queue - Lightweight queue that only runs when required.
Failed/Success callbacks - Allows for more control over messages (return false in the failed callback to resend).
Format Helper - A small utility module that provides markdown support.
Demo
API Overview
DiscordWebhook
https://discordapp.com/api/webhooks/[id]/[token]
webhook DiscordWebhook.new(string webhookId, string webhookToken)
PostHandler webhook:GetPostHandler()
Message webhook:NewMessage()
FormatHelper webhook:GetFromatHelper()
PostHandler
void PostHandler:QueueMessage() – mainly for internal use
void PostHandler:Resume()
void PostHandler:Pause()
void PostHandler:SuccessCallback(function successCallback)
void PostHandler:FailedCallback(function failedCallback)
Message
void Messahge:Send()
void Message:Append(string txt)
void Message:AppendLine(string txt)
void Message:SetUsername(string txt)
void Message:SetAvatarUrl(string url)
void Message:SetTTS(boolean isTTS)
string Message:GetUid()
int Message:CountEmbeds()
AllowedMention Message:GetAllowedMention()
Embed Message:NewEmbed()
AllowedMention
void AllowedMention:AddGlobalMention(string [roles, users, everyone])
void AllowedMention:AddUserId(int id)
void AllowedMention:AddRoleId(int id)
Embed
void Embed:SetTitle(string title)
void Embed:Append(string txt)
void Embed:AppendLine(string txt)
void Embed:SetURL(string url)
void Embed:SetTimestamp([number epoch])
void Embed:SetColor3(Color3 color3)
void Embed:AppendFooter(string txt)
void Embed:AppendFooterLine(string txt)
void Embed:SetFooterIconURL(string url)
void Embed:SetImageURL(string url)
void Embed:SetThumbnailIconURL(string url)
void Embed:SetAuthorName(string name)
void Embed:SetAuthorURL(string url)
void Embed:SetAuthorIconURL(string url)
int Embed:CountFields()
Field Embed:NewField()
Field
void Field:SetName(string name)
void Field:Append(string txt)
void Field:AppendLine(string txt)
void Field:SetIsInline(boolean isInline)
FormatHelper
string FormatHelper:Italic(string txt)
string FormatHelper:Bold(string txt)
string FormatHelper:BoldItalic(string txt)
string FormatHelper:Underline(string txt)
string FormatHelper:UnderlineItalic(string txt)
string FormatHelper:UnderlineBold(string txt)
string FormatHelper:UnderlineBoldItalic(string txt)
string FormatHelper:Strikethrough(string txt)
string FormatHelper:CodeblockLine(string txt)
string FormatHelper:Codeblock(string txt, [string syntax])
string FormatHelper:BlockQuote(string txt)
string FormatHelper:MultiLineBlockQuote(string txt)
string FormatHelper:Spoiler(string txt)
string FormatHelper:URL(string url, [string txt])
Test Script
local discordWebHook = require(script.DiscordWebhook)
--https://discordapp.com/api/webhooks/[id]/[token]
local hook = discordWebHook.new('[id]', '[token]')
local formatHelper = hook:GetFromatHelper()
local avatarUrl = game:GetService('Players'):GetUserThumbnailAsync(1540993, Enum.ThumbnailType.HeadShot, Enum.ThumbnailSize.Size420x420)
-- basic message
local msg = hook:NewMessage()
msg:Append('test')
msg:AppendLine('1')
msg:Append('line2')
msg:SetUsername('Test script')
msg:SetAvatarUrl(avatarUrl)
msg:SetTTS(false)
msg:Send()
-- message with markdown
local msg = hook:NewMessage()
msg:AppendLine(formatHelper:UnderlineBold('Test script'))
msg:AppendLine(formatHelper:Spoiler('Sent from Roblox'))
msg:AppendLine(formatHelper:Codeblock([[
print('Hello world!')
local a = true
if a then
print(a)
end
]], 'Lua'))
msg:SetUsername('Test script')
msg:SetAvatarUrl(avatarUrl)
msg:Send()
-- basic message with mention
local msg = hook:NewMessage()
local allowedMention = msg:GetAllowedMention()
allowedMention:AddGlobalMention('everyone')
msg:SetAvatarUrl(avatarUrl)
msg:Append('test')
msg:AppendLine('1')
msg:Append('line2 @everyone')
msg:SetUsername('Test script')
msg:SetAvatarUrl(avatarUrl)
msg:SetTTS(false)
msg:Send()
-- basic embed
local msg = hook:NewMessage()
msg:SetAvatarUrl(avatarUrl)
local embed = msg:NewEmbed()
embed:SetTitle('basic embed')
embed:Append('test')
embed:AppendLine('1')
embed:Append('line2')
msg:Send()
-- multiple embeds
local msg = hook:NewMessage()
msg:SetAvatarUrl(avatarUrl)
local embed1 = msg:NewEmbed()
embed1:SetTitle('Embed 1')
embed1:Append('embed 1 body')
embed1:SetColor3(Color3.fromRGB(0, 255, 0))
local embed2 = msg:NewEmbed()
embed2:SetTitle('Embed 2')
embed2:Append('embed 2 body')
embed2:SetColor3(Color3.fromRGB(0, 0, 255))
msg:Send()
-- complex embed with fields
local msg = hook:NewMessage()
msg:SetAvatarUrl(avatarUrl)
local embed = msg:NewEmbed()
embed:SetTitle('complex embed')
embed:Append('embed body')
embed:SetURL('https://www.roblox.com/users/1540993/profile')
embed:SetTimestamp(tick() - 86400) -- -1 day
embed:SetColor3(Color3.fromRGB(255, 0, 0))
embed:AppendFooter('embed footer')
embed:SetFooterIconURL(avatarUrl)
embed:SetImageURL(avatarUrl)
embed:SetThumbnailIconURL(avatarUrl)
embed:SetAuthorName('kingdom5')
embed:SetAuthorURL('https://www.roblox.com/users/1540993/profile')
embed:SetAuthorIconURL(avatarUrl)
local field1 = embed:NewField()
field1:SetName('field 1')
field1:Append('body1')
local field2 = embed:NewField()
field2:SetName('field 2')
field2:Append('body2')
local field3 = embed:NewField()
field3:SetName('field 3')
field3:Append('body3')
field3:SetIsInline(true)
local field4 = embed:NewField()
field4:SetName('field 4')
field4:Append('body4')
field4:SetIsInline(true)
msg:Send()
-- message spam test
for i=1, 10 do
local msg = hook:NewMessage()
msg:SetAvatarUrl(avatarUrl)
msg:Append('message spam test ' .. i)
msg:Send()
end
Results:-