Skip to content

Commands

CommandRouter decouples command declaration from the Bot instance. Each command module creates its own router and registers commands against it. The bot merges routers into its registry via attach_router or load_extension.

Usage

from fastapi_interactions import CommandRouter

router = CommandRouter()

@router.command(name="ping", description="Check bot latency")
async def ping(ctx):
    return "Pong!"

Guild Commands

Commands can be scoped to a specific guild for instant propagation during development. Global commands can take up to an hour to appear everywhere, making guild-scoped commands ideal for testing.

Pass a guild_id when creating the router:

from fastapi_interactions import CommandRouter

dev_router = CommandRouter(guild_id="123456789")

@dev_router.command(name="test", description="A test command")
async def test(ctx):
    return "This command only exists in the test server."

Guild-scoped commands appear immediately in the specified server. When ready for production, create a separate router without a guild_id:

from fastapi_interactions import CommandRouter

prod_router = CommandRouter()

@prod_router.command(name="test", description="A test command")
async def test(ctx):
    return "This command is global."

Both routers can coexist:

bot.include_router(dev_router)
bot.include_router(prod_router)

When syncing with bot.sync_commands(), guild-scoped commands are sent to the guild endpoint while global commands are sent to the global endpoint.

Reference

fastapi_interactions.commands.CommandRouter

Source code in fastapi_interactions/commands.py
class CommandRouter:
    def __init__(self, name: str = None, guild_id: Optional[Snowflake] = None):
        self.name = name or self.__infer_name()
        self.guild_id: Optional[Snowflake] = guild_id
        self.commands: dict[str, Command] = {}

    def __infer_name(self) -> str:
        frame = sys._getframe(2)
        return frame.f_globals.get("__name__", "Unknown")

    def __len__(self) -> int:
        return len(list(self.commands.keys()))

    def __str__(self) -> str:
        return f"{list(self.commands.keys())}"

    def command(self, name: str, description: str) -> None:
        """
        Add a slash command to this router.

        The decorated function is registered as the handler for the command
        and will be included when the router is attached to the application.

        Args:
            name: Unique command name.
            description: User-facing command description.

        Example:
            ```python
            @router.command("hello", "Say hello")
            async def hello(ctx):
                return "Hello!"
            ```
        """

        def decorator(func):
            meta = getattr(
                func, "_command_meta", CommandMeta(name="", description="", type=1)
            )
            meta.name = name
            meta.description = description
            self.commands[name] = Command(
                callback=func, meta=meta, guild_id=self.guild_id
            )
            func.__dict__.pop("_command_meta", None)
            return func

        return decorator

command

command(name: str, description: str) -> None

Add a slash command to this router.

The decorated function is registered as the handler for the command and will be included when the router is attached to the application.

Parameters:

Name Type Description Default
name str

Unique command name.

required
description str

User-facing command description.

required
Example
@router.command("hello", "Say hello")
async def hello(ctx):
    return "Hello!"
Source code in fastapi_interactions/commands.py
def command(self, name: str, description: str) -> None:
    """
    Add a slash command to this router.

    The decorated function is registered as the handler for the command
    and will be included when the router is attached to the application.

    Args:
        name: Unique command name.
        description: User-facing command description.

    Example:
        ```python
        @router.command("hello", "Say hello")
        async def hello(ctx):
            return "Hello!"
        ```
    """

    def decorator(func):
        meta = getattr(
            func, "_command_meta", CommandMeta(name="", description="", type=1)
        )
        meta.name = name
        meta.description = description
        self.commands[name] = Command(
            callback=func, meta=meta, guild_id=self.guild_id
        )
        func.__dict__.pop("_command_meta", None)
        return func

    return decorator

fastapi_interactions.commands.Command dataclass

Source code in fastapi_interactions/commands.py
@dataclass(slots=True)
class Command:
    callback: callable
    meta: CommandMeta
    guild_id: Optional[Snowflake] = None

fastapi_interactions.commands.CommandMeta dataclass

Source code in fastapi_interactions/commands.py
@dataclass(slots=True)
class CommandMeta:
    name: str
    description: str
    options: list[CommandOption] = field(default_factory=list)
    type: int = 1

    def as_payload(self):
        return {
            "name": self.name,
            "description": self.description,
            "type": self.type,
            "options": [option.as_payload() for option in self.options],
        }

fastapi_interactions.commands.CommandOption dataclass

Source code in fastapi_interactions/commands.py
@dataclass
class CommandOption:
    name: str
    description: str
    type: OptionType = OptionType.STRING
    required: bool = True

    def as_payload(self):
        return {
            "name": self.name,
            "description": self.description,
            "type": self.type,
            "required": self.required,
        }