본문 바로가기

개발 이야기/실무 Recipe

[slack-bot] incoming webhook 만들기

 

incoming webhook을 사용하면 슬랙 외부에서도 특정 채널에 메시지를 보낼 수 있다.

webhook으로 메시지를 보내려면 JSON 데이터와 함께 http request로 요청하면 된다. 

이때, text만 보내거나 'attachments'라고 하여 그냥 text보다 더 구조적인 데이터를 보낼 수 있다. 

 

아래 사진에서 빨간색 줄로 표시된 *블록이 attachments이다.

 

*block: slack document에서 많이 보게 될 용어이다. 메시지의 구성 요소 하나하나를 말한다. slack에서 block마다 사용할 수 있는 필드들이 정해져있다. block kit builder를 사용하면 메시지 템플릿도 고를 수 있고, 어떻게 block을 만들어야 하는지 확인할 수도 있다.

 

봇이 정기적으로 잔액을 조회한 뒤 채널에 알려준다. 

 

 

 


 

1. 앱 생성

- api.slack.com/apps 에서 앱 생성 ('create an app' 클릭)

- workspace를 선택할 땐, 알림을 보내고 싶은 채널이 있는 워크스페이스를 선택한다.

 

만약 앱을 만든 워크스페이스가 아닌 다른 곳에 채널이 있다면 manage distribution에서 체크리스트를 채운 다음 active public distribution을 한 뒤 워크스페이스에 앱을 추가하면 된다. 이건 나중에 불특정 다수에게 DM을 보내는 슬랙봇도 포스팅할 예정인데, 거기서 다뤄보도록 하겠다.

 

 

 

2. 좌측 메뉴바 - basic information - display information 수정

 

앱이 어떻게 보여질지 수정하면 된다. 아이콘은 512*512 또는 2000*2000 픽셀 사이즈여야 하는데, image resize 사이트에서 원하는 이미지를 리사이징하고 넣는다. 이 과정을 안거치면 워크스페이스에 봇을 추가할 수 없다. 

 

+ 이름이 마음에 안드는 경우 나중에 좌측 features 메뉴 - App Home - Your App's Presense 에서 변경 가능하다.

 

 

 

3. build incoming webook

 

- 스크롤을 올려서 add features and functionality - incoming webhook을 클릭한다.

-  activate incoming webhook의 스위치 on

- 맨 아래 Add new Webhook to Workspace 클릭한다.

- workspace에서 봇이 메시지를 날릴 채널을 선택한다.

 

 

incoming-webhook 봇이 채널에 접근할 수 있도록 permission을 요청한다.

 

 

 

4. send message

 

channel을 추가하면 webhook url을 알 수 있다. 

 

 

 

terminal 또는 postman으로 요청해서 메시지가 오는지 확인할 수 있다. 

postman / webhook url에 요청한다.

 

 

 

5. attachments

 

좀 더 구조화된 메시지를 보내고 싶다면 text 대신 attachment를 사용한다.

 

{
  "attachments": [
      {
          "fallback": "요청 실패 시 보낼 메시지",
          "color": "#2eb886",
          "pretext": "attachment block 위에 나타낼 text",
          "author_name": "roseline",
          "author_link": "https://github.com/roseline124",
          "author_icon": "https://avatars.githubusercontent.com/u/41788121?s=460&u=ee6a6f6499aa68a23947cfb76d5e9cb6eebfd29c&v=4",
          "title": "attachments 사용법",
          "title_link": "https://api.slack.com/",
          "text": "attachment block 안에 보여줄 메시지",
          "fields": [
              {
                  "title": "필드",
                  "value": "value",
                  "short": false
              }
          ],
          "image_url": "http://my-website.com/path/to/image.jpg",
          "thumb_url": "http://example.com/path/to/thumb.png",
          "footer": "Slack API",
          "footer_icon": "https://platform.slack-edge.com/img/default_application_icon.png",
          "ts": 123456789
      }
  ]
}

 

 

 

 

 

6. programmatic하게 메시지 보내기

 

정기적으로, 또는 특정 이벤트가 발생했을 때 메시지를 보내려면 코드를 짜서 요청한다.

정기적으로 보내고 싶다면 AWS의 Codebuild나 lambda 또는 crontab을 사용할 수 있다.

 

import axios from 'axios'
import format from 'date-fns/format'

const API_URL = 'https://api-url.com'
const SLACK_WEBHOOK_URL = 'https://your-slack-webhook-url.com'

const sendMessage = async () => {
  const response = await axios.get(API_URL)

  if (response.data.error) {
    const attachment = {
      pretext: '⚠️요청이 실패했습니다.',
      color: '#FF0000',
      title: '에러 메시지',
      text: response.data.error.message,
      fields: [{ title: '에러 코드', value: response.data.error.code, short: false }],
    }
    await axios.post(SLACK_WEBHOOK_URL , { attachments: [attachment] })
    return
  }

  const balance = Number(response.data.balance)
  // 화폐 단위에 맞게 숫자에 컴마를 넣어준다.
  const balanceCurrency = new Intl.NumberFormat('ko-KR').format(balance)
  const currentTime = format(new Date(), 'yyyy-MM-dd HH:mm')
  const message = `${currentTime} 현재 잔액은 ${balanceCurrency} 원입니다.`
  await axios.post(SLACK_WEBHOOK_URL , { text: message })
}

export default sendMessage 

 

 

7. github action을 사용해서 정기적으로 돌리기

 

액션 스크립트에 on:schedule을 추가하여 정기적으로 코드를 실행할 수 있다. 

프로젝트를 생성하고 라이브러리를 설치한다. date-fns는 없어도 된다. 

 

// 프로젝트 폴더 생성
mkdir incoming-webhook

// 프로젝트 생성
npm init -y

// 라이브러리 설치
npm i axios date-fns

// git 연결
git init
git switch -c main
git add . && git commit -m "add sendMessage and workflow"
git push --set-upstream origin main

 

 

- sendMessage.js

 

현재 시간을 슬랙으로 보내주는 함수를 만들고 실행하는 스크립트이다.

점심 시간이 되면 칼같이 알려주는 봇이다. 직장인의 점심 시간은 1분 1초가 중요하니까. 후후. 

 

const axios = require("axios");

const SLACK_WEBHOOK_URL = "slack-webhook-url";

const sendMessage = async () => {
  const currentTime = format(new Date(), "yyyy-MM-dd HH:mm");
  const message = `12시 점심 시간입니다. 그만 일하고 점심 드세요!`;
  await axios.post(SLACK_WEBHOOK_URL, { text: message });
};

(async () => {
  await sendMessage();
})();

 

파일을 추가했으면 package.json의 scripts에 send-message 스크립트를 추가한다.

"send-message": "node ./sendMessage.js"

 

 

 

- .github/workflows/slackbot.yml 파일을 생성한다.

 

name: Send Message

on:
  schedule:
    # UTC 오전 3시 마다 돌아감 -> 한국 시간 12시
    # https://crontab.guru/#0_3_*_*_*
    - cron: "0 3 * * *"

  # github action에서 수동으로 액션을 돌릴 수 있다.
  workflow_dispatch:

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout branch
        uses: actions/checkout@v2

      - name: Use Node.js
        uses: actions/setup-node@v1
        with:
          node-version: "12.18.3"

      - name: Send message
        run: |
          npm i
          npm run send-message

 

 

근데 위와 같이 간단한 코드라면 action-slack-notify 액션을 써도 된다.

슬랙 웹훅 URL은 깃허브 시크릿에 넣어야 한다. 

 

github project - settings - secrets 에서 추가한다. 

name: Crawler Test

on:
  schedule:
    # UTC 오전 7시 마다 돌아감 -> 한국 시간 4시
    # https://crontab.guru/#0_7_*_*_*
    - cron: "0 7 * * *"

  workflow_dispatch:

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout branch
        uses: actions/checkout@v2

      - name: Lunch Time Notification
        uses: rtCamp/action-slack-notify@master
        env:
          SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}
          SLACK_CHANNEL: random
          SLACK_MESSAGE: '얼른 일어나세요!'
          SLACK_TITLE: 점심시간입니다
          SLACK_USERNAME: slackbot test