glyde/rest/route

A route is the rate-limit identity of a call. glyde/rest/seg is the only way to build one: alongside the path from typed segments, or read back out of a path string with seg.from_path. Both walk the same segment rules, so two spellings of one endpoint cannot land in two buckets.

Types

Discord’s major parameters. Two channels have independent buckets for the same endpoint; two messages in the same channel do not.

pub type Major {
  NoMajor
  ChannelMajor(String)
  GuildMajor(String)
  WebhookMajor(id: String, token: WebhookToken)
}

Constructors

  • NoMajor
  • ChannelMajor(String)
  • GuildMajor(String)
  • WebhookMajor(id: String, token: WebhookToken)

    Id and token together. The token is absent on the GET /webhooks/{webhook.id} form, where Discord takes the id alone.

Opaque because class is derived from template. A record update could move one and leave the other, and a route that wrongly claims to be an interaction callback skips the global limit.

pub opaque type Route

Discord’s undocumented per-resource sublimits. Invisible in the headers: a 429 with a large retry_after on a bucket that still claims capacity.

pub type Sublimit {
  NoSublimit
  Named(String)
  Aged(created_at_ms: Int)
}

Constructors

  • NoSublimit
  • Named(String)

    A named subset of an endpoint: “name-or-topic” on PATCH /channels/{id} is 2 per 10 minutes.

  • Aged(created_at_ms: Int)

    Deleting a message older than two weeks lands in a different bucket (discord-api-docs#1295). The limiter has the clock, so it resolves this.

A live credential that is also half a major parameter. A closure, not a field, because echo and string.inspect read straight through an opaque record. Reaching the bucket key is the one thing it still has to do, so key and major_key return the token in plain text and everything else does not.

pub opaque type WebhookToken

Values

pub const channel_placeholder: String
pub const guild_placeholder: String
pub const id_placeholder: String

Any id that is not a major parameter. Discord buckets these together, so they need no name of their own.

pub fn key(route: Route, now_ms now_ms: Int) -> String

The provisional bucket key, until x-ratelimit-bucket names the real one. Holds the webhook token on a webhook route, so keep it out of logs.

pub fn major(route: Route) -> Major
pub fn major_key(route: Route) -> String

The major half of the key, to pair with Discord’s x-ratelimit-bucket hash. Holds the webhook token on a webhook route, so keep it out of logs.

pub fn method(route: Route) -> http.Method
pub fn new(
  method: http.Method,
  template: String,
  major: Major,
  sublimit: Sublimit,
) -> Route

Every route goes through here, so the one endpoint Discord exempts from the global limit is recognised in a single place.

pub const opaque_placeholder: String

Text that is neither an id nor a literal: an interaction token, an invite code.

pub const reaction_placeholder: String

A reaction emoji and everything after it.

pub fn route_key(route: Route, now_ms now_ms: Int) -> String

The route half of the key. Discord reports one hash per route and the real bucket is that hash paired with the major parameter, so both halves exist.

pub fn same_major(one: Major, other: Major) -> Bool

Whether two majors name the same bucket. Major holds a closure, and comparing closures with == does not answer this question.

pub fn sublimit(route: Route) -> Sublimit
pub fn template(route: Route) -> String

The unsubstituted template, e.g. “/channels/{channel.id}/messages”.

pub fn unbound(route: Route) -> Bool

Exempt from the global limit and in no bucket. True for interaction callbacks and nothing else.

pub const webhook_placeholder: String
pub fn webhook_token(
  token: option.Option(String),
) -> WebhookToken

None is the tokenless GET /webhooks/{webhook.id} form.

pub const webhook_token_placeholder: String

Half of a webhook’s major parameter, which has no business in a template.

pub fn with_sublimit(route: Route, sublimit: Sublimit) -> Route

The one part of a route a caller may change: a path cannot know how old the message it deletes is.

Search Document