Sup. We've heard the community feedback and want to take some steps in reducing the number of necessary data lookups when using interactions. One of the most common suggestions was turning IDs into resolved objects in the interactions payload. Here's how we're thinking of doing that.
- IDs that are requested as arguments in a command will stay just IDs
- You will also receive a new
resolved
field on interactions that include the objects that correspond to those IDs - The top-level
guild_id
andchannel_id
will not be resolved
For arguments, here are the data fields you will receive:
- Member: the guild member object, if we can resolve one, without a user
- User: the full user object (always returned if requested)
- Channel: a partial channel object containing
id
,type
,name
, andpermissions
(which is the computed permissions for the invoking user in that channel, including overwrites) - Role: the full role object
These fields will be resolved into a resolved object on the top level of the interaction model. resolved contains a dictionary of object types (channels, users, etc) that each contain a dictionary of id to resolved object.
Here's an example payload:
{
"type": 2,
"token": "A_UNIQUE_TOKEN",
// all standard iteraction stuff in the docs
"id": "786008729715212338",
"guild_id": "290926798626357999",
"channel_id": "645027906669510667",
"data": {
"name": "cardsearch",
"id": "771825006014889984",
"options": [
{
"name": "role",
"value": "53908232506183680"
},
{
"name": "channel",
"value": "53908232506183680"
},
{
"name": "user",
"value": "53908232506183680"
},
],
"resolved": {
"members": {
"53908232506183680": { // the member object }
},
"users": {
"53908232506183680": { // the user object }
},
"roles": {
"53908232506183680": { // role object }
},
"channels": {
"53908232506183680": { // partial channel object }
}
}
}
}
We looked through the models and reasoned about whether or not there was a use case for sending this data every time about the invoking channel or guild. Ultimately, we felt that the most-needed data was present elsewhere in the interactions payload.
More specifically, we reasoned that bots that needed specific information about an object would request it as an argument. For example, if you are using /ban
, you don't need to know the topic or name of the invoking channel. You will want to know information about the target channel, if there is one, which is why we are resolving some of those fields (with room to add more if necessary).
Furthermore, a lot of the important information about the request is present in other parts of the interaction payload. For example, you can use member.permissions
to check the invoker's permissions without needing to know every role on the guild and do the math yourself. While there are bots that want to know things like invoking channel or guild name, or topic, etc. it is not a common enough use case to send that data to every bot, and we felt those were best left to individual GET
requests and caching.
However, now that we have this system, there is room in the future if it's necessary.
One, we can do it without a breaking change, which is nice. However, making a breaking change here would've been fine.
The server is always going to receive only the id
from the client. Clients are not authoritative sources of data, so we need to do the lookups server-side.
So, we've got a bunch of IDs. There are two ways to do this:
- Resolve them into a separate object
- Resolve them in place
Resolving them in place (replacing IDs with objects) requires us to loop over the nested structure and sequentially query for each object, which are blocking operations, and would mean the user waits a long time to get a response.
Putting the resolved objects into the resolved
field allows us to do asynchronous mass-lookups of data and stuff them all into an object when they're complete. This scales much better, especially when planning ahead for things like array-type arguments.