Skip to content

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.

go
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 channelID and messageID.
  • Use WithReason on 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.

go
message, _ := b.FetchMessage(ctx, messageID, channelID)

Correct:

go
message, err := b.FetchMessage(ctx, channelID, messageID)
if err != nil {
	return err
}

Incorrect: dereferencing a failed lookup.

go
guild, _ := b.CachedGuild(id)
fmt.Println(guild.Name)

Correct:

go
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) and FetchGuild(context.Context, snowflake.ID) (*guilds.Guild, error) access guilds.
  • CachedChannel(snowflake.ID) (*channels.Channel, bool) and FetchChannel access channels.
  • CachedUser(snowflake.ID) (*users.User, bool) and FetchUser access users.
  • CachedMember(guildID, userID snowflake.ID) (*users.Member, bool) and FetchMember(context.Context, guildID, userID snowflake.ID) (*users.Member, error) access guild members.
  • CachedMessage(snowflake.ID) (*messages.Message, bool) and FetchMessage(context.Context, channelID, messageID snowflake.ID) (*messages.Message, error) access messages.
  • User() *users.User, AppID() snowflake.ID, ReadyAt() time.Time, Uptime() time.Duration, and RestClient() *rest.Client expose bot identity, readiness state, and the REST client. RestClient() returns the same client as the public Bot.Rest field.
  • Bot.Rest *rest.Client exposes direct REST methods such as GetChannelMessage, GetGuild, GetUser, GetGuildMember, and the many channel, guild, command, webhook, and interaction operations.
  • rest.StringPtr(string) *string is a convenience helper for the many REST parameter fields that use *string (for example, EditMessageParams.Content and ModifyChannelParams.Name).
  • rest.WithReason(context.Context, string) context.Context attaches an audit log reason; ReasonFromContext retrieves it.

Examples ​

Released under the Apache License 2.0.