Background
We are developing a Slack Bot. This time we are using Bolt for JavaScript (Node.js) provided by Slack, React, Next.js, and ngrok. Here is what each of them does.
- Bolt for JavaScript: I don't want to use Slack's bare-bones API, but want to benefit from the function that wraps it.
- React: Needed to use Next.js
- Next.js: Slack needs a request URL to notify my bot app when events such as mentions occur in Slack, but Next.js makes it easy to create an API endpoint to be set to that URL (e.g. /api/something)
- ngrok: In the local development environment, that URL will be
http://localhost:3000
, so the protocol will behttp
instead ofhttps
. Slack does not allow this, so we need a URL that starts with https that tunnels to the localhttp://localhost:3000
. ngrok provides that easily!
Problem to be solved.
I have already confirmed that if I type @xxxx
in a certain workspace in Slack, the event is notified to https://xxxx.jp.ngrok.io/api/slack/events
. However, in this API file
app.event("app_mention", async ({ event, say }) => {
.
.
.
}
is not invoked and the following error occurs
error - unhandledRejection: Error: listen EADDRINUSE: address already in use :::3000
I would like to know why and how to resolve this.
Source code
/api/slack/events.ts
import type { NextApiRequest, NextApiResponse } from "next";
require("dotenv").config();
import app from "../../../config/slackAuth";
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
// Unique case for Slack challenge
if (req.body.challenge) return res.status(200).json(req.body);
// Subscribe to 'app_mention' event in your App config
// See https://api.slack.com/tutorials/tracks/responding-to-app-mentions
app.event("app_mention", async ({ event, say }) => {
try {
// Response to the message in the thread where the event was triggered with @${message.user}
// See https://slack.dev/bolt-js/concepts#message-sending
await say({
text: `Hi <@${event.user}>!`,
thread_ts: event.ts,
});
} catch (error) {
await say({
text: `<@${event.user}> ${error.message}.`, // @userName Request failed with status code 429.
thread_ts: event.ts,
});
}
});
(async () => {
// Start this app
await app.start(process.env.PORT || 3000);
console.log("⚡️ Bolt app is running!");
})();
return res.status(404).json({ message: "Unknown event type" });
}
Error code
error - unhandledRejection: Error: listen EADDRINUSE: address already in use :::3000
at Server.setupListenHandle [as _listen2] (net.js:1331:16)
at listenInCluster (net.js:1379:12)
at Server.listen (net.js:1465:7)
at C:\Users\81906\Documents\slackGpt3\node_modules\@slack\bolt\dist\receivers\HTTPReceiver.js:176:25
at new Promise (<anonymous>)
at HTTPReceiver.start (C:\Users\81906\Documents\slackGpt3\node_modules\@slack\bolt\dist\receivers\HTTPReceiver.js:142:16)
at App.start (C:\Users\81906\Documents\slackGpt3\node_modules\@slack\bolt\dist\App.js:241:30)
at eval (webpack-internal:///(api)/./pages/api/slack/events.ts:69:69)
at handler (webpack-internal:///(api)/./pages/api/slack/events.ts:71:7)
at Object.apiResolver (C:\Users\81906\Documents\slackGpt3\node_modules\next\dist\server\api-utils\node.js:363:15) {
code: 'EADDRINUSE',
errno: -4091,
syscall: 'listen',
address: '::',
port: 3000
}
Issue
Using Slack Bolt for JavaScript with Next.js is not straightforward due to the following reasons:
This information was provided by someone at Slack, and the source can be found at https://github.com/slackapi/bolt-js/issues/1687.
Solution