tadpole/rest/endpoints

The first REST endpoint bindings: things every bot does in its first hour — read itself, post a message, reply. Each function builds the request, runs it through tadpole/rest/execute, and decodes the typed model. Transport injection is inherited from execute; the plain functions use the real httpc transport, the _with variants accept any transport (tests, proxies, a future JS target).

Every call runs in a fresh execute session, so rate-limit state learned here does not carry between calls: single-call bots are fine, sustained-fire callers should use execute.send_in_session directly.

When you reach for this

Any other route: drop to tadpole/rest/execute with rest.post/rest.get and decode the payload yourself.

Routes

FunctionDiscord routeReturns
get_current_userGET /users/@meUser
send_messagePOST /channels/{channel_id}/messagesMessage
replyPOST /channels/{channel_id}/messages, body carries message_referenceMessage

The _with variants take the same routes over an injected transport; see each function’s doc.

Failure modes

Errors arrive already mapped by execute:

Discord truncates content past 2000 characters, silently: the message posts, the tail is gone, no error returns. Check string.length yourself if the length matters.

Concurrency

Each call is independent and blocks its process for the round trip plus any sleeps. The fresh-session caveat above is the one that bites: a tight loop leans on 429 retries rather than learned waits. Sustained fire on one route belongs in execute.send_in_session.

See also

Values

pub fn get_current_user(
  client: rest.RestClient,
) -> Result(user.User, error.TadpoleError)

GET /users/@me — the bot’s own user object.

Fails with RestStatus when Discord answers non-2xx (401 means the token is wrong or was reset), with the status-0 RestStatus convention on transport failure, or with DecodeFailed if Discord’s payload stops matching the user model.

pub fn get_current_user_with(
  client: rest.RestClient,
  transport: fn(request.Request(String)) -> Result(
    response.Response(String),
    execute.TransportError,
  ),
) -> Result(user.User, error.TadpoleError)

get_current_user over an injected transport.

pub fn reply(
  client: rest.RestClient,
  channel_id: ids.ChannelId,
  message_id: ids.MessageId,
  content: String,
) -> Result(message.Message, error.TadpoleError)

POST /channels/{channel_id}/messages with a message_reference — Discord’s reply. The replied-to message shows the reference in the client; the returned message’s message_type is 19 (REPLY).

pub fn reply_with(
  client: rest.RestClient,
  transport: fn(request.Request(String)) -> Result(
    response.Response(String),
    execute.TransportError,
  ),
  channel_id: ids.ChannelId,
  message_id: ids.MessageId,
  content: String,
) -> Result(message.Message, error.TadpoleError)

reply over an injected transport.

pub fn send_message(
  client: rest.RestClient,
  channel_id: ids.ChannelId,
  content: String,
) -> Result(message.Message, error.TadpoleError)

POST /channels/{channel_id}/messages — post content to a channel.

Discord silently truncates content past 2000 characters: the message still goes through, the tail is gone, no error is returned. Tadpole does not second-guess that — check string.length yourself if it matters.

Concurrency note: each call carries its own rate-limit session, so hammering this in a loop relies on 429 retries rather than learned waits. See the module doc.

pub fn send_message_with(
  client: rest.RestClient,
  transport: fn(request.Request(String)) -> Result(
    response.Response(String),
    execute.TransportError,
  ),
  channel_id: ids.ChannelId,
  content: String,
) -> Result(message.Message, error.TadpoleError)

send_message over an injected transport.

Search Document