Discord Slash Commandをつくる
Tags: discord, discordslashcommand
Published: 2021-07-21 14:32:34

---
title: Discord Slash Commandをつくる
published: true
tags: Discord, DiscordSlashCommand

---

DiscordのSlashコマンドを使ってみます。

https://discord.com/developers/docs/interactions/slash-commands

## アプリの作成

https://discord.com/developers/applications

Developer PortalのApplicationsから新規作成します。

![6cdf0c93-e499-491a-a1aa-b897f9dde692](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/72pg79nxx91rj0jbdreo.png)
 
作成したら、OAuth2の設定ページに遷移して、OAuth2 URL Generatorの下にあるSCOPESから `Bot`, `applications.commands` を選択して、さらに `Bot Permissions` の `Send Meesages` にチェックを入れます。（必要に応じて追加でチェックを入れてください）

![336c21e0-e3b4-48b5-9080-7803bafa178a](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8bbvazx1jwgyq5vaoya3.png)

SCOPESにあるURLにアクセスしてBOTユーザをサーバーに招待します。
 
ここでBOTの下準備は完了です。

## スラッシュコマンドの登録

https://discord.com/developers/docs/interactions/slash-commands#registering-a-command

公式のドキュメントにある通りスクリプトを組んで実行します。

```python
import requests

url = "https://discord.com/api/v8/applications/<APPLICATION ID>/guilds/<GUILD ID>/commands"

json = {
    "name": "blep",
    "description": "Send a random adorable animal photo",
    "options": [
        {
            "name": "animal",
            "description": "The type of animal",
            "type": 3,
            "required": True,
            "choices": [
                {
                    "name": "Dog",
                    "value": "animal_dog"
                },
                {
                    "name": "Cat",
                    "value": "animal_cat"
                },
                {
                    "name": "Penguin",
                    "value": "animal_penguin"
                }
            ]
        },
        {
            "name": "only_smol",
            "description": "Whether to show only baby animals",
            "type": 5,
            "required": False
        }
    ]
}

headers = {
    "Authorization": "Bot <BOT TOKEN>"
}

r = requests.post(url, headers=headers, json=json)
print(r.status_code)
```

特定のサーバーでのみ使用するのであれば `<GUILD ID>` を指定します。
このスクリプトを実行して成功すれば201が表示されて終了します。
特定のサーバーでのみのコマンドであれば即時反映されるので、実際にDiscord上でも確認ができます。`/` を入力すると候補に `/blep` が表示されるはずです。

![1cb19898-9309-4d47-97bd-790333eed9fe](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9bh6di572z4esjsgj8gu.png)

ただこのままコマンドを送信してもエラーとなり何も発生しないので、ひとまずコマンドを送信したらBOTがメッセージを送信する処理を実装します。

## コマンド送信後の実装

今回、本番環境では Cloudflare Workers KV を使用します。GoogleCloudRunなどのサーバレスのものを利用しても問題ないですが、CloudRunはアクセスがあってから起動するまでに時間がかかってしまい、Discord側でタイムアウト判定になってしまう可能性があります。Cloudflare Workers KVは起動がCloudRunよりもかなり早いので正常にレスポンスできるはずです。

https://www.cloudflare.com/ja-jp/products/workers-kv/

Cloudflare Workers KVのセットアップは割愛します。https://developers.cloudflare.com/workers/ に環境構築からデプロイまでかかれています。
外部ライブラリを利用するのでWebpackも利用します。

### Discordのリクエストを受け付ける

`discord-interactions` を使って実装します。

https://www.npmjs.com/package/discord-interactions

{% gist https://gist.github.com/YutaGoto/3c405a57e75cf49bef52add74452b3d1 %}

このコードは何かしらコマンドのリクエストがあれば `pong` を返却するだけのものになっています。

![スクリーンショット 2021-07-21 AM1.09.05](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f8hu9lwzsoswoendbe6s.png) 

以下のコードでヘッダーがちゃんとDiscordから来たものかを判定します。Discordで `Interactions Endpoint URL` を登録する際にあえて誤ったリクエストヘッダーがついたリクエストがくるので、それの判定を行います。

```js
const valid = verifyKey(
  await request.clone().arrayBuffer(),
  request.headers.get('X-Signature-Ed25519'),
  request.headers.get('X-Signature-Timestamp'),
  discord_public_key
)

if (!valid) {
  return new Response('', { status: 401 })
}
```

以降の処理は正しい形式でJSONを返却します。 https://discord.com/developers/docs/interactions/slash-commands#responding-to-an-interaction にもサンプルが書いています。

### デプロイ

外部パッケージを使用しているのでwebpackした後のコードをデプロイします。webpackやその設定の説明は端折ります。

デプロイもcloudflareのチュートリアルにある通りにコマンド一発で完了します。 https://developers.cloudflare.com/workers/get-started/guide#8-publish-your-project

デプロイが完了したらCloudflareのWorkers一覧ページにアクセスして、そこに表示されているURLを確認します。

![Screenshot 2021-07-21 at 01-21-22 Workers Account Cloudflare - Web Performance Security](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7zw641l7icpolkw110j7.png)

そこに表示されているURLを Discordのアプリケーション設定ページの `discord-interactions` にペーストしてセーブしてチェックがパスしたら完了です。