Resource Access
Overview
The Bot resource helpers provide a consistent cache-first or REST-backed way to retrieve common Discord objects: guilds, channels, users, guild members, and messages. They are convenience methods, not a replacement for the complete REST surface exposed by Bot.Rest.
Architecture
Cached* methods perform local typed lookups and never make a network request. Fetch* methods call the corresponding REST endpoint with the supplied context, return the typed object, and hydrate the configured typed cache on success. The bot returns copies for the current bot user through User, but fetched resource objects are the values decoded by REST.
Quick Start
This complete program fetches the invoking user and replies with its username.
package main
import (
"log"
"os"
"github.com/discord-go/discord.go/bot"
"github.com/discord-go/discord.go/intents"
)
func main() {
token := os.Getenv("DISCORD_TOKEN")
if token == "" {
log.Fatal("DISCORD_TOKEN is required")
}
router := bot.NewRouter()
router.Command("whoami", "Fetch the invoking user", func(ctx *bot.InteractionContext) {
user := ctx.User()
if user == nil {
_ = ctx.Reply("No user ID was present")
return
}
fetched, err := ctx.Bot.FetchUser(ctx.Context(), user.ID)
if err != nil {
log.Printf("fetch user: %v", err)
_ = ctx.Reply("The user could not be fetched")
return
}
_ = ctx.Reply("You are " + fetched.Username)
})
b := bot.New(token, bot.WithIntents(intents.Guilds), bot.WithRouter(router))
if err := b.Run(); err != nil {
log.Fatal(err)
}
}For normal application code, attach a cache as shown in
Creating/Configuration
Configure a cache with WithCache if local lookups are useful. The helpers use the bot's Rest client, so WithRESTClient can provide a custom HTTP client or rate-limit store. All fetch methods accept a context.Context; use a deadline for command work that depends on external REST calls.
Using
Basic: fetch one resource
Call FetchGuild, FetchChannel, FetchUser, FetchMember, or FetchMessage with the IDs required by the REST endpoint. Check the returned error before reading the pointer.
Intermediate: cache-first
Try the matching Cached* method first, then fetch on a miss. A successful fetch will populate the configured typed cache.
Advanced: use Bot.Rest
When the helper does not cover an operation, use Bot.Rest directly. Examples include listing messages, editing channels, managing roles, fetching audit logs, or calling application command endpoints. Use the REST endpoint guide to choose the exact signature.
Common Patterns
- Use
ctx.Context()from an event context so cancellation follows the bot run. - Pass snowflake IDs rather than string paths to high-level helpers.
- Fetch a message by both
channelIDandmessageID. - Use
WithReasonon REST contexts for supported audit-log operations. - Cache only objects the application can usefully reuse.
Best Practices
Use the narrowest helper
Why: typed helpers make required IDs and returned resources explicit.
Pros: less endpoint construction and fewer serialization mistakes.
Cons: a new Discord endpoint may not have a high-level wrapper yet.
Use context deadlines
Why: REST calls can stall independently of gateway dispatch.
Pros: handlers remain responsive and shutdown can complete.
Cons: a short deadline can turn a temporarily slow API into a user-visible failure.
Distinguish cache freshness from REST success
Why: a cache hit may be stale while a fetch failure does not make the old value invalid automatically.
Pros: consistency decisions remain in application code.
Cons: callers must define when stale data is acceptable.
Common Mistakes
Incorrect: passing a message ID where a channel ID is required.
message, _ := b.FetchMessage(ctx, messageID, channelID)Correct:
message, err := b.FetchMessage(ctx, channelID, messageID)
if err != nil {
return err
}Incorrect: dereferencing a failed lookup.
guild, _ := b.CachedGuild(id)
fmt.Println(guild.Name)Correct:
guild, ok := b.CachedGuild(id)
if !ok {
guild, err = b.FetchGuild(ctx, id)
if err != nil {
return err
}
}
fmt.Println(guild.Name)API Walkthrough
CachedGuild(snowflake.ID) (*guilds.Guild, bool)andFetchGuild(context.Context, snowflake.ID) (*guilds.Guild, error)access guilds.CachedChannel(snowflake.ID) (*channels.Channel, bool)andFetchChannelaccess channels.CachedUser(snowflake.ID) (*users.User, bool)andFetchUseraccess users.CachedMember(guildID, userID snowflake.ID) (*users.Member, bool)andFetchMember(context.Context, guildID, userID snowflake.ID) (*users.Member, error)access guild members.CachedMessage(snowflake.ID) (*messages.Message, bool)andFetchMessage(context.Context, channelID, messageID snowflake.ID) (*messages.Message, error)access messages.User() *users.User,AppID() snowflake.ID,ReadyAt() time.Time,Uptime() time.Duration, andRestClient() *rest.Clientexpose bot identity, readiness state, and the REST client.RestClient()returns the same client as the publicBot.Restfield.Bot.Rest *rest.Clientexposes direct REST methods such asGetChannelMessage,GetGuild,GetUser,GetGuildMember, and the many channel, guild, command, webhook, and interaction operations.rest.StringPtr(string) *stringis a convenience helper for the many REST parameter fields that use*string(for example,EditMessageParams.ContentandModifyChannelParams.Name).rest.WithReason(context.Context, string) context.Contextattaches an audit log reason;ReasonFromContextretrieves it.
Examples
Related APIs
caching.mdfor cache implementations and TTLs.client.mdforBot.Restconfiguration.../low-level/models/README.mdfor resource models.