Next.jsからSlackに通知を送る
Next.jsからSlackのチャンネルに通知を送る方法
**Next.jsとはVercelが作成しているReactのフレームワークです。**面倒な設定を書かなくてもすぐに使えるZero Configを標榜しており、実際にwebpackやTypeScriptと一緒にReactを書く際にも特別な準備は不要です。SSRにも対応しており、Reactで開発するならNext.jsかFacebook製のCreate React Appを使うのがスタンダードになっています。
関連記事: Google Apps ScriptからSlackとLINEを連携するbotを作る手順を紹介します
また、**Slackとは、主にIT企業で導入されている非同期コミュニケーションが可能なチャットツールです。**様々なツールと連携できるところに特徴があり、サーバーの監視ログやあらゆる通知をSlackのチャンネルに集約できます。
この記事ではNext.jsからSlackに通知を送る方法を紹介します。
SlackのWebhook URLを漏れないようにする
**Slackに通知を送るにはWebhook URLを取得します。**始めはWebhook URLをブラウザからPOSTすれば簡単に実現できると考えていました。
しかし、ブラウザでWebhook URLにPOSTする際にユーザーがWebhook URLを知ることができることに思い至り、フロントからSlackに通知する方法は避けました。
それでも実現方法を考えていると、Next.jsのAPIの機能を使ってサーバー側からコードを実行すればWebhook URLが漏れてしまう問題を解決できることに思い至りました。そこで、実際に本記事の方法で実装しました。
Webhook URLを.envに設定する
まずはSlackチャンネルのWebhook URLを環境変数に設定します。
SLACK_WEBHOOK_URL=https://hooks.slack.com/services/XXXXXXXXXXXX
SLACK_WEBHOOK_URL
の値はprocess.env.SLACK_WEBHOOK_URL
で取得します。なお.envに記述した環境変数は、Next.jsの中でどこからでも呼び出し可能です。しかし、配信されるJSにで値が公開されることはありません。
また、チャンネル毎のWebhook URLの取得方法は「slackのincoming-webhookに登録する」をご覧ください。
node-slack-sdkでWebhookにPOSTする
**Slackに通知を送るには、SlackのWebhook URLにPOSTリクエストをするということを書きました。**この処理はSlack公式のnode-slack-sdkというnodeモジュールを利用すると簡単に書くことができます。
lib/slack.ts
に以下のようなコードを記述します。
import { IncomingWebhook } from '@slack/webhook'
const slack = {
sendToSlack: async (text: string) => {
const url = process.env.SLACK_WEBHOOK_URL
const webhook = new IncomingWebhook(url)
await webhook.send({ text })
},
}
export default slack
api/comments.tsにPOSTリクエストを送る
lib/slack.ts
で作成したモジュールはNode.jsで動作します。Next.jsでは、apiを通じてサーバーサイドのコードを実行できます。
Next.jsでは、pages/api
配下に作成したファイルがAPIのエンドポイントになります。/api/comments
というエンドポイントを作りたいときは、pages/api/comments.ts
というファイルを置くことでパスとファイルを自動的にマッピングされます。
pages/api/comments.tsを作成する
まず、pages/api/comments.ts
を作成します。ここで上記で作成したslackモジュールを実行します。
import { NextApiRequest, NextApiResponse } from 'next'
import slack from 'lib/slack'
module.exports = async (req: NextApiRequest, res: NextApiResponse) => {
const { message } = req.body
if (typeof message === 'undefined') {
res.writeHead(400).end('Invalid body: message')
}
if (req.method === 'POST') {
// Slackのチャンネルにテキストを通知する
await slack.sendToSlack(message)
res.writeHead(201).end('Created')
} else {
// POST以外のメソッドは受け付けない
res.writeHead(405).end('Method Not Allowed')
}
}
これで/api/comments
にPOSTリクエストをするとSlackにメッセージを投稿できるようになりました。
エンドポイント/api/commentsにPOSTする
また、POSTリクエストにはfetchを使います。
const message = 'メッセージを投稿します'
fetch('/api/comments', {
method: 'POST',
mode: 'same-origin',
credentials: 'same-origin',
headers: { 'Content-Type': 'application/json; charset=utf-8' },
body : JSON.stringify(message),
})
変数messageはSlackに送りたい文字列を格納してください。
[実践]ユーザーが投稿したコメントをSlackに通知する
では、実際にNext.jsからSlackに通知を送ります。ユースケースとして、「ユーザーが投稿したコメントをSlackに通知する」ことを想定します。
import React, { useState, SyntheticEvent } from 'react'
import { NextPage } from 'next'
type Props = {
comment: string
handleChange: (e: SyntheticEvent) => void
handleSubmit: (e: SyntheticEvent) => void
}
const Component: React.FC<Props> = (props) => (
<form onSubmit={props.handleSubmit}>
<input
type="text"
placeholder="コメントを入力..."
value={props.comment}
onChange={props.handleChange}
/>
<button type="submit">投稿する</button>
</form>
)
const Container: NextPage<{}> = () => {
const [comment, setComment] = useState('')
const handleChange = (e) => setComment(e.target.value)
const handleSubmit = async (e) => {
e.preventDefault()
if (comment.trim() === '') {
return
}
fetch('/api/comments', {
method: 'POST',
mode: 'same-origin',
credentials: 'same-origin',
headers: { 'Content-Type': 'application/json; charset=utf-8' },
body : JSON.stringify({message: comment}),
})
}
return <Component {...{comment, handleChange, handleSubmit}} />
}
Container.displayName = 'IndexPage'
export default Container
エンドポイント/api/comments
にPOSTでユーザーが投稿するコメントを送信するReactコンポーネントが作成できました。
「投稿する」ボタンを押すと、入力したメッセージがSlackに通知されます。
まとめ
Next.jsからSlackに通知を送る方法を紹介しました。なお、以下に記述したコードはサーバーサイドだけで実行され、bundleするJSには含まれません。
pages/api
配下に作成したファイルgetServerSideProps
やgetStaticProps
といったReactコンポーネントにデータを注入するための関数
Next.jsはフロントエンドとサーバーサイドの境界をうまく区切っているフレームワークですね。さらにNext.jsを使いこなしていきましょう。
Happy Coding 🎉