Getting Started¶
Where do we start?¶
Before we begin getting started on everything else, it is recommended to check out the quickstart page first to get a basic grip on making slash commands for your bot.
Making a slash command.¶
The basics.¶
First, let’s explain by how commands are parsed through the Discord Bot API.
As you may know, Discord relies a lot on the interaction of HTTP Requests and JSON tables. As is with the case here, commands are the exact same way with having JSON tables to structure the design of it for Discord to understand. We can apply this information likewise with how slash commands are to be designed in the Python code. Below attached is from the Discord Developer Portal on Slash Commands for showing how they are designed.
Field |
Type |
Description |
name |
string |
1-32 character name matching |
description |
string |
1-100 character description. |
options? |
array of ApplicationCommandOption |
if the option is a subcommand or subcommand group type, this nested options will be the parameters. |
This table shows us the way that Discord handles the structure of commands for slash commands through their Bot API. For visualization purposes, we’ll quickly make a JSON example (although we won’t be using it) in order to explain how this works:
{
"name": "test",
"description": "This is just a test command, nothing more.",
}
Now that we have a basic understanding of how the JSON table works, we can take this knowledge and convert it into a decorator method for the Python code as shown below:
@slash.slash(name="test",
description="This is just a test command, nothing more.")
async def test(ctx):
await ctx.send(content="Hello World!")
Now that we’ve gone over how Discord handles the declaration of slash commands through their Bot API, let’s go over what some of the other things mean within the logical part of our code, the command function:
Giving some options for variety.¶
The next thing that we will begin to talk about is the implementation of options, otherwise well-known as “arguments” in discord.py commands.
The JSON structure of options are designed up to be similar to the same premise of how a slash command is declared. Below is the given table of how an option JSON would appear as:
Field |
Type |
Description |
type |
int |
value of ApplicationCommandOptionType. |
name |
string |
1-32 character name matching |
description |
string |
1-100 character description. |
default? |
bool |
the first required option for the user to complete–only one option can be default. |
required? |
bool |
if the parameter is required or optional–default |
choices? |
array of ApplicationCommandOptionChoice |
choices for |
options? |
array of ApplicationCommandOption |
if the option is a subcommand or subcommand group type, this nested options will be the parameters. |
Now we have an idea of how options are declared. With this in mind, let’s quickly make a JSON example in order to visualize this concept even further:
{
"name": "test",
"description": "This is just a test command, nothing more.",
"options": [
{
"name": "optone",
"description": "This is the first option we have.",
"type": 3,
"required": "false"
}
]
}
While the table in the basics mentions an array in particular called ApplicationCommandOptionType
,
there isn’t that much of an explanation on how this works. Let’s put this into better laymen
terms on what this means with a table below showing all of these values:
Name |
Value |
SUB_COMMAND |
1 |
SUB_COMMAND_GROUP |
2 |
STRING |
3 |
INTEGER |
4 |
BOOLEAN |
5 |
USER |
6 |
CHANNEL |
7 |
ROLE |
8 |
MENTIONABLE |
9 |
FLOAT |
10 |
The purpose of having the ApplicationCommandOptionType
value passed into our option JSON structure
is so that we can help the Discord UI understand what kind of value we’re inputting here. For instance,
if we’re wanting to put in a string response, we’ll pass the ID 3 so that the UI of Discord chat bar
knows to format it visually this way. If we’re looking for a user, then we’ll pass ID 6 so that it presents
us with a list of users in our server instead, making it easier on our lives.
This is not to be confused, however, with formatting the response type itself. This is merely a method so that the API wrapper can help us with passing the correct type or instance variable with the arguments of the command function’s code.
Now, we can finally visualize this by coding an example of this being used in the Python code shown below.
from discord_slash.utils.manage_commands import create_option
@slash.slash(name="test",
description="This is just a test command, nothing more.",
options=[
create_option(
name="optone",
description="This is the first option we have.",
option_type=3,
required=False
)
])
async def test(ctx, optone: str):
await ctx.send(content=f"I got you, you said {optone}!")
Additionally, we could also declare the type of our command’s option through this method shown here:
from discord_slash.model import SlashCommandOptionType
(...)
option_type=SlashCommandOptionType.STRING
More in the option? Give them a choice.¶
Alas, there is also a way to give even more information to options with Discord’s Slash Commands: a choice. Not like something that you’re given at birth of when you become of legal age as an adult, we’re not here to give you that kind of life advice, but the choice of what value you want your option to rather pass. Below is a table that shows the JSON structure of how choices are represented for an option:
Field |
Type |
Description |
name |
string |
1-32 character choice name. |
value |
string or int |
value of the choice, up to 100 characters if string. |
This time, only 2 fields are able to be passed for this. Below is a JSON example of how this would be designed:
{
"name": "ChoiceOne",
"value": "Hello command, this is my value!"
}
To make it really simple, the name
field is only to be used for how you want the choice to be presented
through Discord’s UI. It’s the “appearance” of how you want your choice shown, not the actual returned value
of it. Hence, this is why value
is the second field passed for that, which can be either in the form of
a string or integer. Below is an implementation of this design in the Python code:
from discord_slash.utils.manage_commands import create_option, create_choice
@slash.slash(name="test",
description="This is just a test command, nothing more.",
options=[
create_option(
name="optone",
description="This is the first option we have.",
option_type=3,
required=False,
choices=[
create_choice(
name="ChoiceOne",
value="DOGE!"
),
create_choice(
name="ChoiceTwo",
value="NO DOGE"
)
]
)
])
async def test(ctx, optone: str):
await ctx.send(content=f"Wow, you actually chose {optone}? :(")
Want to restrict access? Setup permissions!¶
Slash commands also support the ability to set permissions to allow only certain roles and/or users to run a slash command. Permissions can be applied to both global and guild based commands. They are defined per guild, per top-level command (the base command for subcommands), and each guild can have multiple permissions. Here is the table that shows the JSON structure of how permissions are represented:
Field |
Type |
Description |
id |
int |
Snowflake value of type specified. Represents the target to apply permissions on. |
type |
int |
|
permission |
boolean |
|
How the type parameter works is very simple. Discord has many ids to represent different things. As you can set permissions to apply for User or Role, ApplicationCommandPermissionType is used. It’s a number and following table shows the supported id types for permissions:
Name |
Value |
Role |
1 |
User |
2 |
This is an example of how a single permission will look when represented as a json object:
{
"id": 12345678,
"type": 1,
"permission": True
}
Now, let take a look at an example. The slash command decorator has a permissions parameter where
it takes in a dictionary. The key being the guild id to apply permissions on, and value being the list
of permissions to apply. For each permission, we can use the handy create_permission
method to
build the permission json explained above.
In this case, we are setting 2 permissions for a guild with an id of 12345678
. Firstly, we are allowing
role with id 99999999
and disallowing user with id 88888888
from running the slash command.
from discord_slash.utils.manage_commands import create_permission
from discord_slash.model import SlashCommandPermissionType
@slash.slash(name="test",
description="This is just a test command, nothing more.",
permissions={
12345678: [
create_permission(99999999, SlashCommandPermissionType.ROLE, True),
create_permission(88888888, SlashCommandPermissionType.USER, False)
]
})
async def test(ctx):
await ctx.send(content="Hello World!")
Alternatively, you can use the @slash.permission
decorator to define your guild permissions for the
command as show in the following example:
from discord_slash.utils.manage_commands import create_permission
from discord_slash.model import SlashCommandPermissionType
@slash.slash(name="test",
description="This is just a test command, nothing more.")
@slash.permission(guild_id=12345678,
permissions=[
create_permission(99999999, SlashCommandPermissionType.ROLE, True),
create_permission(88888888, SlashCommandPermissionType.USER, False)
])
async def test(ctx):
await ctx.send(content="Hello World!")
Nested commands as subcommands.¶
Before you get into learning how to create a subcommand, please be sure to read up on the documentation above given for how slash commands are made.
Subcommands are way to “nest” your slash commands under one (or more) given names, as either a “base” name or a “grouping” of an existing base. When this is said, it will initially appear very confusing. Let’s use the table shown below as a way to introduce the new fields/properties that can be applied for a slash command to become a subcommand:
Field |
Type |
Description |
base |
string |
The name of the subcommand “base.” |
subcommand_group |
string |
The name for the group of commands under the “base.” Field is optional. |
base_description |
string |
The description when the base is active in the UX chat bar. Defaults to |
subcommand_group_description |
string |
The name for the group of commands under the “base.” Defaults to |
This table is importantly distinguishing the library’s naming conventions and not the way that th eDiscord API handles it. The API does subcommand grouping and bases through the options of a slash command, so we decided to create a decorator instead to make this easy for bot developers alike to use. We will not be giving a JSON example of this because of this reason.
# This will appear as "/bot latency" as latency is not an option,
# but apart of the command name itself.
@slash.subcommand(base="bot",
name="latency",
description="Returns the bot's latency.")
async def bot_latency(ctx):
await ctx.send(f"Hello! {round(bot.latency * 1000)} ms.")
If you would like to add a group instead, you may simply base the subcommand_group`
kwarg into the decorator. Please note that the slash command limit is 25 commands per subcommand group per subcommand base. (Laymen’s term for 25 subcommands in a group, and 25 groups in a base. This is not a global exception and may also apply as a limitation for guild commands.)
Handling my errors.¶
Thankfully, we try to make a majority of our error handling very simple. If you would like to learn more about how to handle your errors, please refer to our errors page. If you are looking for listener events, then check our listeners page instead.
As a side-note, as of version 3.0, message/menu commands (context menus) are handled under the on_slash_command_error
event.