slack bot 생성 및 코드 작성하기 (command, modal 기능)

괭이밥·2025년 6월 3일
0

slack bot 프로젝트

목록 보기
1/2
post-thumbnail

📌 개요

slack은 프로젝트, 기업에서 흔히 사용하는 메신저 어플이다.

slack을 사용하는 여러 이유가 있겠지만, 쉽고 빠르게 여러 어플리케이션과 연동할 수 있는 확장성이 대표적인 이유일 것이라 생각된다.

그 중 커스텀의 끝판왕 slack bot을 직접 만든다면 slack을 통해 여러 업무를 일원화하거나 반복적인 업무를 자동화 할 수 있다.

이번 글에서는 slack bot을 생성하고, python을 통해 bot을 제어하는 코드를 작성하여 나만의 커스텀 봇을 만드는 방법에 대해 작성해보았다.

목표

  • slack bot 생성
  • slack bot의 command 기능추가
  • slack bot의 command 동작을 위한 백엔드 개발 (with. python)
  • slack bot의 modal 생성을 위한 Interactivity 기능 추가
  • slack bot의 modal 동작을 위한 백엔드 개발

Slack bot 생성하기

1️⃣ slack bot 생성

  1. 아래 링크로 접속하여 Create App 클릭

  2. From scratch 클릭

  3. slack app 이름과 슬랙 워크스페이스 선택

여기까지하면 봇(slack app) 생성은 완료된 것이다.
권한과 기능을 추가해보자.

2️⃣ 권한 추가하여 token 발급받기!

  1. OAuth & Permissions에서 Bot Token Scopes 추가

    아래와 같이 5개의 권한을 추가했다.
  • channels:read - 공개 채널 목록을 읽을 수 있는 권한
  • chat:wirte - slack bot이 채팅 메세지를 보낼 수 있는 권한
  • command - command 기능을 사용하기 위한 권한
  • groups:read - 비공개 채널 목록을 읽을 수 있는 권한
  • incoming-webhook - 외부에서 slack bot이 채널에 메세지를 전송하기 위한 권한
  1. Insall App으로 이동하여 봇을 워크 스페이스에 추가
    권한을 추가하면서 Slack 워크스페이스에 App을 추가할 수 있게 되었다.
    버튼을 클릭하면 워크스페이스에 앱이 추가된 것을 볼 수 있다.

  2. OAuth Token 발급 확인
    해당 토큰은 추후 api server 개발할 때 필요한 값이므로 기억해주자.

  3. 채널에 slack bot을 추가
    slack bot이 특정 채널에 메세지를 보낼 수 있도록 채널에 slakc bot을 추가해주자.

    위에서 워크스페이스에 bot을 추가했다면 앱에서 봇을 볼 수 있다.
    해당 봇 우클릭을 해주어 앱 세부정보 보기 클릭한다.

    이 앱을 채널에 추가 클릭하여 원하는 채널에 봇을 추가해준다.
    더해서 채널 ID는 추후 개발할 때 필요한 값이므로 기억해두자.

이제 slack bot의 기본적인 셋팅을 마쳤다.
하나씩 기능을 추가면서 slack bot을 커스텀해보자.



기능 추가

여기에서 slack bot의 command와 Interactivity 두 가지 기능을 사용했는데, 각 기능은 다음과 같다.

  • Command: 특정 명령어 입력하면 bot 동작 (e.g. 위에서 언급한 /alerts 동작)
  • Interactivity: 버튼과 같은 modal 설정

command입력이나 버튼을 눌렀을 때 어떤 동작을 하는지 정의하는 api server를 개발해주어야 한다.

하나씩 차근차근 진행해보겠다.

➕ Webhooks 기능 추가

먼저 봇이 채팅방에 메세지 보내는 것을 활성화 해보자.

Incomming Webhooks 메뉴에서 Activate Incoming Webhooks 활성화를 해준다.

아래 curl을 통해 봇이 메세지 채팅방에 메세지 가는지 간단하게 테스트할 수 있다.
그 전에 기능을 추가하면 봇을 업데이트 해주어야 사용 가능하다.

채널을 선택하고 허용을 눌러 업데이트를 진행해준다.

➕ Slash Command 기능 추가

나만의 command를 만들어보자.

그 전에 command 기능이 어떻게 동작하는지 헷갈릴 수 있으므로, 한번 짚어보자.

1. slack에서 command 입력 (e.g. /alerts)
2. slack은 설정한 API 서버에 요청 (e.g. https://<api-server>/alerts)
3. API 서버 내부 동작 후 Slack Response 형식에 맞게 반환
4. slack은 response를 받음
  1. Slash Command 메뉴에서 Create New Command 클릭
  1. command 설정
keydescription
Command생성할 명령어 정의
Request URLAPI 서버 URL 작성
Slack의 경우 HTTS만 지원함
Short Description해당 명령어에 대한 간단한 설명
Uasge Hint명령어 사용 힌트
파라미터가 있는 경우, 힌트를 통해 대략적으로 어떻게 사용하는지 알려줄 수 있음

여기서 가장 어려운 것은 Request URL로 예상된다.
API 서버에 HTTS를 적용하기 위해 도메인과 SSL 인증서 설정이 필요하기 때문이다.

나의경우 간단한 테스트를 진행할 때는 ngrok을 사용하였다.
ngrok 사용은 블로그에 포스팅 한 내용을 참고하면 된다.

  1. API 서버 개발 (코드 작성)

slack 채팅방에 /alerts을 입력하면 지정한 Request URL로 API 호출이 일어난다.
해당 API을 처리하는 로직을 개발해보자.

여기서 python 프레임 워크인 flask를 사용하였다.
먼저 개발에 필요한 flaks, slack python sdk 모듈을 pip로 설치해주자.

pip install Flask

pip install slack_sdk

아래는 /alerts 경로의 API를 개발한 코드 예시이다.

from flask import Flask, request, jsonify
from slack_sdk import WebClient
import logging

app = Flask(__name__)

channel = "<your-slack-channel-id>"  # slack bot이 채팅 보낼 채널 ID 설정
token = "<your-slack-bot-token>"  # slack bot 토큰 설정 (위에서 발급받은 토큰)
slack_client = WebClient(token=token)  # slack bot 설정


# Reuqest URL에 입력한 path 정의
@app.route("/alerts", methods=["POST"])
def alerts():
    try:
        # slack 채팅방에 보낼 메시지 형태, blocks라고 부르며 자세한 낸용은 공식 홈페이지 참고
        blocks = [
            {
                "type": "section",
                "text": {"type": "mrkdwn", "text": "*Alert List*"},
            },
            {
                "type": "divider"
            },
            {
                "type": "section",
                "text": {"type": "mrkdwn", "text": "- alert1\n- alert2"}
            }
        ]

        # slack 채널에 blocks 전송
        slack_client.chat_postMessage(channel=channel, text="", blocks=blocks)
        return "", 200  # 성공적으로 끝남

    except Exception as e:
        logging.error(f"Error - /alerts: {e}")
        return jsonify({"error": str(e)}), 500  # 에러 발생 시 실패 반환


if __name__ == "__main__":
    app.run(debug=True, port=3000)

여기서 slack blocks라는 개념이 낯설 것이다.
slack blocks란 slack 메신저로 텍스트, 버튼, 이미지 등을 전송하기 위한 규격이라고 생각하면 된다.

아래 공식 사이트에서 더 자세하게 확인이 가능하며, 내가 원하는 템플릿으로 설계할 수 있다.

동작 확인

spack app이 설치되어 있는 채팅방에 명령어를 입력한다.

이 때 slack은 나의 API 서버로 요청하며, API 서버에서 내가 정의한 코드를 실행한뒤 blocks를 채팅방에 보낸다.
나의 경우 옆에 Silences라는 버튼이 있는 blocks을 보내도록 하였다.

이제 Silence 버튼을 누르면 실제도 동작하는 기능을 추가해보자.

해당 설정은 command가 아닌 Interactivity에서 진행된다.

➕ Interactivity 기능 추가

버튼, 모달에서 submit 기능을 사용하기 위해 Interactivity & Shortcuts 메뉴에서 Interactivity 활성화를 해준다.

Interactivity를 활성해주면, Command에서와 동일하게 Request URL을 작성해야 한다.
나는 /slack/interactions 경로로 api가 호출되도록 설정했다.
이제 모든 버튼, 모달의 요청은 /slack/interactions으로 요청하게 된다.

Button 동작 코드 작성

silence 버튼을 누르면 모달 창을 띄우도록 동작하는 코드를 작성해보자.

@app.route("/slack/interactions", methods=["POST"])  # /slack/interactions으로 들어온 요청 처리
def slack_interactions():
    payload = request.form.get("payload")  # Request body 추출
    interaction_data = json.loads(payload)

    interaction_type = interaction_data.get("type")  # interactions 타입 추출

    # 어떤 타입의 요청인지 확인
    if interaction_type == "block_actions":  # 버튼 타입  ---> silence 버튼 요청은 여기 해당
        return handle_block_actions(interaction_data)

    elif interaction_type == "view_submission":  # 모달의 submit 타입  ---> 아래에서 설명
        return handle_view_submission(interaction_data)

    return jsonify({"error": "Unknown interaction type"}), 400


# 버튼 타입일 때 처리
def handle_block_actions(interaction_data):
    actions = interaction_data["actions"]
    trigger_id = interaction_data["trigger_id"]  # 모달 열기 위한 trigger_id

    for action in actions:
        action_id = action["action_id"]

        # action_id가 silence button일 때 동작, action_id는 blocks에서 정의
        if action_id == "silence_button":  
            
            # modal을 열기 위한 view 정의, 공식 홈페이지 참고하여 커스텀
            view = view = {
                "type": "modal",  # modal type임을 명시
                "title": {"type": "plain_text", "text": "Silence Alert"},  # modal 타이틀 정의
                "close": {"type": "plain_text", "text": "Close"},  # modal아래의 close 정의
                "submit": {"type": "plain_text", "text": "Submit"},  # modal 아래의 submit 정의
                "blocks": [
                    # modal에 들어갈 blocks 정의
                ]
            }

            slack_client.views_open(trigger_id=trigger_id, view=view)  # 슬랙에 modal open


        return "", 200    

모달 정의는 view 변수에 정의하면 되며, 공식 홈페이지에서 더 자세히 확인할 수 있다.

이제 Silence 버튼 클릭 시 /slack/interactions으로 요청이 가고, 코드에서 정의한 모달(view)이 뜨는 것을 볼 수 있다.

Submit 동작 코드 작성

모달에서 Submit 버튼 클릭하면 버튼 이벤트와 동일하게 /slack/interactions 경로로 api 호출이 일어난다.

위에서 작한 코드에 이어서 작성해주면 되는데, interaction_type이 view_submission으로 분기를 태워주면 된다.

@app.route("/slack/interactions", methods=["POST"])  # /slack/interactions으로 들어온 요청 처리
def slack_interactions():
    payload = request.form.get("payload")  # Request body 추출
    interaction_data = json.loads(payload)

    interaction_type = interaction_data.get("type")  # interactions 타입 추출

    # 어떤 타입의 요청인지 확인
    if interaction_type == "block_actions":  # 버튼 타입 
        return handle_block_actions(interaction_data)

    elif interaction_type == "view_submission":  # 모달의 submit 타입  ---> submit 버튼 요청은 여기 해당
        return handle_view_submission(interaction_data)

    return jsonify({"error": "Unknown interaction type"}), 400

def handle_view_submission(interaction_data):
    callback_id = interaction_data["view"]["callback_id"]

    # callback_id를 통해 silence_modal에서 온 요청임을 확인, modal의 blocks에서 정의
    if callback_id == "silence_modal":  
        # 내부 동작 코드 작성
        # ~~~

        # 내부 동작 완료 후 채팅방에 완료 안내 메세지 전송
        text = "✅ Silence 설정이 성공적으로 처리되었습니다."
        slack_client.chat_postMessage(channel=self.channel, text=text)


        return "", 200  

위의 코드는 Submit을 누르면 slack bot이 있는 채널에 메세지를 보내는 동작을 한다.
실제로 Submit 눌렀을 때 채널에 메세지가 온 것을 볼 수 있다.


마치며

이번 글에서 slack bot을 생성하고, command와 modal기능을 추가하고 기능 동작을 위한 코드를 작성하였다.

위에서 서술한 기능 외에 다양한 기능을 제공하고 있으니 slack 공식 docs를 보며 좀 더 고도화된 slack bot을 만들 수 있을 것이다.

profile
개발도 하고 싶은 클라우드 엔지니어

0개의 댓글