λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°
Kotlin

[Kotlin] Slack API둜 μŠ¬λž™ 채널에 Message λ°œμ†‘ν•˜κΈ°

by 주발2 2022. 3. 27.
λ°˜μ‘ν˜•

πŸ“Ž Slack API둜 μŠ¬λž™ μ±„널에 Message λ³΄λ‚΄κΈ°

μ•ˆλ…•ν•˜μ„Έμš”, 이번 μ‹œκ°„μ—λŠ” μŠ¬λž™μ—μ„œ μ œκ³΅λ˜λŠ” APIλ₯Ό 톡해 Java μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜μ—μ„œ Slack 채널에 λ©”μ‹œμ§€λ₯Ό 전솑해보도둝 ν•˜κ² μŠ΅λ‹ˆλ‹€.

 

ν”„λ‘œμ νŠΈλ₯Ό μš΄μ˜ν•˜λ‹€λ³΄λ©΄ νŠΉμ • 문제(둜그, μ—λŸ¬, λ©”λͺ¨λ¦¬, 배치 μ‹€νŒ¨ λ“±)κ°€ λ°œμƒν–ˆμ„ λ•Œ μ΄λŸ¬ν•œ λ¬Έμ œμ μ„ λ°”λ‘œ 확인할 수 μžˆλ„λ‘ μž₯애에 λŒ€ν•΄μ„œλŠ” μ•Œλ¦Όμ„ λ°›μ•„ 문제λ₯Ό ν™•μΈν•˜λŠ” 것이 μ€‘μš”ν•˜λ‹€κ³  μƒκ°ν•˜λŠ”λ°μš”, μ΄λŸ¬ν•œ μ•Œλ¦Ό 쀑 ν•˜λ‚˜κ°€ μŠ¬λž™μ„ ν™œμš©ν•˜λŠ” λ°©λ²•μž…λ‹ˆλ‹€.

μŠ¬λž™μ˜ 경우 λ§Žμ€ κΈ°μ—…μ—μ„œ μ‚¬μš©ν•˜κ³  있고, λ˜ν•œ ꡉμž₯히 λ§Žμ€ κΈ°λŠ₯을 μ œκ³΅ν•˜κ³  μžˆλŠ”λ°μš”, μ΄λŸ¬ν•œ κΈ°λŠ₯을 ν™œμš©ν•˜λ©΄ λ¬΄κΆλ¬΄μ§„ν•˜κ²Œ μ»€μŠ€ν…€μ„ ν•  수 μžˆμ„ 것 κ°™μŠ΅λ‹ˆλ‹€.

 

ν•΄λ‹Ή ν¬μŠ€νŒ…μ—μ„œλŠ” μŠ¬λž™μ„ λ‹€μš΄λ°›κ±°λ‚˜ νšŒμ›κ°€μž…ν•˜λŠ” λ“±μ˜ 기본적인 섀정을 μ œμ™Έν•œ μŠ¬λž™μ— 메세지λ₯Ό λ°œμ†‘ν•˜κΈ° μœ„ν•œ μ„€μ •λΆ€ν„° λ°œμ†‘ μ½”λ“œκΉŒμ§€ μ²˜μŒλΆ€ν„° λκΉŒμ§€ μ‚΄νŽ΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

 

 

Slack App 생성

λ‹€μŒ μ‚¬μ΄νŠΈμ—μ„œ Create New App을 톡해 App을 μƒμ„±ν•΄μ€λ‹ˆλ‹€.

(μŠ¬λž™μ„ κ°€μž…ν•˜κ±°λ‚˜ μƒμ„±ν•˜λŠ” λ“± 초기 λ‹¨κ³„λŠ” λ”°λ‘œ μ„€λͺ…ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. μŠ¬λž™ 채널은 기본으둜 public으둜 μƒμ„±ν•˜μ˜€μœΌλ‚˜ private둜 μƒμ„±ν•˜μ—¬λ„ 방법은 μžˆμŠ΅λ‹ˆλ‹€. μ•„λž˜μ—μ„œ μ„€λͺ…λ“œλ¦΄κ²Œμš”.)

쒌츑 사진은 기쑴에 App을 μƒμ„±ν•œ κ²½μš°κ°€ μžˆλŠ” 화면이고, 우츑 사진은 App을 처음 μƒμ„±ν•˜λŠ” ν™”λ©΄μž…λ‹ˆλ‹€.

 

 

λ‹€μŒμœΌλ‘œ From scratchλ₯Ό ν΄λ¦­ν•©λ‹ˆλ‹€.

 

 

App Nameκ³Ό workspaceλ₯Ό μ„€μ •ν•˜κ³  Create App을 ν΄λ¦­ν•˜μ—¬ 앱을 μƒμ„±ν•©λ‹ˆλ‹€.

(workspace의 경우 μŠ¬λž™μ—μ„œ μ•Œλ¦Όμ„ λ°›κ³ μž ν•˜λŠ” μ›Œν¬νŽ˜μ΄μŠ€λ₯Ό μ„ νƒν•˜μ‹œλ©΄ λ©λ‹ˆλ‹€.)

 

 

Scopes μ„€μ • 및 Token λ°œκΈ‰

그럼 μœ„μ™€ 같은 μ΄ˆκΈ°ν™”λ©΄μ΄ λ‚˜μ˜¬ν…λ°μš”, OAuth Tokensλ₯Ό λ°œκΈ‰λ°›κΈ° μœ„ν•΄ OAuth & Permissionsλ₯Ό ν΄λ¦­ν•©λ‹ˆλ‹€.

 

κΆŒν•œ(Authentication)에 λŒ€ν•΄ κΆκΈˆν•˜μ‹œλ‹€λ©΄ μ•„λž˜ 링크λ₯Ό μ°Έκ³ ν•΄μ£Όμ„Έμš” πŸ˜ƒ

 

μœ„ ν™”λ©΄μ—μ„œ OAuth Scopeλ₯Ό μ„€μ •ν•©λ‹ˆλ‹€.

μ €λŠ” channels:read, chat:write, users:writeλ₯Ό μ„ νƒν–ˆλŠ”λ°μš”,

  • channels:read - μ›Œν¬μŠ€νŽ˜μ΄μŠ€μ˜ public 채널에 λŒ€ν•œ 정보 보기
  • chat:write - SlackApi둜 message λ°œμ†‘
  • users:write - SlackApiλ₯Ό μœ„ν•œ presence(?) μ„€μ •

μŠ¬λž™ 채널에 λ©”μ‹œμ§€λ₯Ό 보내기 μœ„ν•΄μ„œλŠ” chat:writeλŠ” λ°˜λ“œμ‹œ μΆ”κ°€λ₯Ό ν•΄μ•Όν•©λ‹ˆλ‹€.

μœ„ μ„€μ • 외에도 더 λ§Žμ€ 섀정듀이 μ‘΄μž¬ν•˜λŠ”λ°μš”, μžμ„Έν•œ 사항은 λ¬Έμ„œμ—μ„œ 확인할 수 μžˆμŠ΅λ‹ˆλ‹€ :)

 

 

+ ν˜Ήμ‹œ μŠ¬λž™ 채널을 private둜 μ„€μ •ν•˜μ‹€ 경우, groups:read Scopeλ₯Ό μΆ”κ°€μ μœΌλ‘œ μ„€μ •ν•΄μ£Όμ…”μ•Ό ν•©λ‹ˆλ‹€.

 

 

OAuth Scope 섀정을 마친 ν›„ μœ„λ‘œ μ˜¬λΌκ°€μ„œ Install to Workspaceλ₯Ό ν΄λ¦­ν•˜μ—¬ OAuth Tokens을 λ°œκΈ‰λ°›μŠ΅λ‹ˆλ‹€.

β€» Token은 μΈμ¦ν‚€λ‘œ μ‚¬μš©λ  μš©λ„λ‹ˆ λ°˜λ“œμ‹œ μ™ΈλΆ€λ‘œ λ…ΈμΆœν•΄μ„œλŠ” μ•ˆλ˜λ©° κ°œμΈλ³΄κ΄€μ„ ν•΄μ•Ό ν•©λ‹ˆλ‹€.

Slack의 Bot Token은 xoxb- ν˜•μ‹μž…λ‹ˆλ‹€.

 

 

Slack에 μ•± μ„€μ •

λ‹€μŒμœΌλ‘œ μœ„μ—μ„œ μƒμ„±ν•œ Slack App을 μ±„λ„μ—μ„œ 직접 앱을 λ“±λ‘ν•©λ‹ˆλ‹€.

  • μ•Œλ¦Όμ„ λ°›κ³ μž ν•˜λŠ” 채널 우클릭 > 채널 세뢀정보 μ—΄κΈ° > 톡합 > μ•± μΆ”κ°€ 클릭
  • μœ„μ—μ„œ μ„€μ •ν•œ μ›Œν¬μŠ€νŽ˜μ΄μŠ€(SlackApi) μΆ”κ°€

 

μ•Œλ¦Όμ„ 섀정받을 Channel ID κ°’ μ–»κΈ°

이곳에 μ ‘κ·Όν•˜μ—¬ μœ„μ—μ„œ 얻은 Bot Token인 xoxb~의 토큰값을 μœ„ 빨간색 λ„€λͺ¨λ°•μŠ€μ— μ„€μ •ν•˜κ³  ν•˜λ‹¨μ— Test method λ²„νŠΌμ„ ν΄λ¦­ν•˜μ—¬ μŠ¬λž™μ˜ 정보λ₯Ό ν™•μΈν•©λ‹ˆλ‹€.

 

그럼 μœ„μ™€ 같이 μŠ¬λž™μ˜ 정보λ₯Ό 확인할 수 μžˆμŠ΅λ‹ˆλ‹€.

idκ°€ μŠ¬λž™ λ©”μ‹œμ§€μ— λ°œμ†‘ν•  λ•Œ ν•„μš”ν•œ μ±„λ„μ˜ id이고, λ°”λ‘œ μ•„λž˜ name은 μŠ¬λž™ 채널λͺ… μž…λ‹ˆλ‹€.

id값은 μ½”λ“œ μž‘μ„±ν•  λ•Œ ν•„μš”ν•œ κ°’μ΄λ―€λ‘œ, λ°œμ†‘ν•  μ±„λ„μ˜ id값을 λ”°λ‘œ λ³΄κ΄€ν•©λ‹ˆλ‹€.

 

 

+ ν˜Ήμ‹œ private 채널을 ν™•μΈν•˜κ³  싢은 경우, μœ„μ—μ„œ Scope에 groups:readλ₯Ό μ„€μ •ν•˜μ‹  ν›„

types에 private_channelλ₯Ό μž…λ ₯ν•˜λ©΄ 정보λ₯Ό 확인할 수 μžˆμŠ΅λ‹ˆλ‹€.

 

μŠ¬λž™ μ±„널에 Message λ°œμ†‘ν•˜κΈ°

μ—¬κΈ°κΉŒμ§€ ν•˜μ…¨μœΌλ©΄ μŠ¬λž™μ— λ©”μ‹œμ§€λ₯Ό λ°œμ†‘ν•˜κΈ° μœ„ν•œ μ…‹νŒ…μ€ λμž…λ‹ˆλ‹€.

이제 Kotlin μ½”λ“œλ₯Ό μž‘μ„±ν•˜μ—¬ μŠ¬λž™μ— λ©”μ‹œμ§€λ₯Ό λ³΄λ‚΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

(ν…ŒμŠ€νŠΈ ν•˜κΈ° μœ„ν•œ μ½”λ“œμ΄λ―€λ‘œ μ½”λ“œλ˜ν•œ ꡉμž₯히 λ‹¨μˆœν•œλ°μš” μ‹€μ œλ‘œλŠ” νˆ¬ν‘œμ™€ 같은 λ²„νŠΌμ„ λ°œμ†‘ν•˜κ±°λ‚˜, 이미지, 파일, λ©”μΌλ°œμ†‘ λ“± λ‹€μ–‘ν•˜κ²Œ μ»€μŠ€ν…€ν•˜μ—¬ 메세지λ₯Ό λ°œμ†‘ν•  수 μžˆμŠ΅λ‹ˆλ‹€.)

 

λ¨Όμ € slack-api-client 라이브러리 μ˜μ‘΄μ„±μ„ μΆ”κ°€ν•©λ‹ˆλ‹€.

// Gradle
implementation("com.slack.api:slack-api-client:1.20.2")

// Maven
<dependency>
    <groupId>com.slack.api</groupId>
    <artifactId>slack-api-client</artifactId>
    <version>1.20.2</version>
</dependency>

 

λ‹€μŒμœΌλ‘œ ν…ŒμŠ€νŠΈλ₯Ό 보내기 μœ„ν•œ μ½”λ“œλ₯Ό μž‘μ„±ν•©λ‹ˆλ‹€.

interface SlackService {
    fun sendMessage(text: String)

    fun sendMessage(channel: String, text: String)
}


import com.slack.api.Slack
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Service

@Service
class SlackServiceImpl : SlackService {

    private val log = LoggerFactory.getLogger(javaClass)

    @Value("\${slack.bot.token}")
    lateinit var token: String

    @Value("\${slack.monitor.channel.token}")
    lateinit var defaultChannel: String

    override fun sendMessage(text: String) {
        sendMessage(defaultChannel, text)
    }

    /**
     * Send Slack Alarm
     */
    override fun sendMessage(channelId: String, text: String) {
        val client = Slack.getInstance().methods()
	runCatching {
            client.chatPostMessage {
                it.token(token)
                    .channel(channelId)
                    .text(text)
            }
        }.onFailure { e ->
            log.error("Slack Send Error: {}", e.message, e)
        }
    }
    
    /**
     * Slack Channel name, id list
     */
    fun showSlackInfo() {
        val client = Slack.getInstance().methods()
        var result: ConversationsListResponse = ConversationsListResponse()
        kotlin.runCatching {
            result = client.conversationsList {
                it.token(token)
            }
        }.onSuccess {
            result.channels.stream().forEach {
                log.info("{} -> {}", it.name, it.id)
            }
        }
    }
}

μ‚¬μ΄λ“œ ν”„λ‘œμ νŠΈλ₯Ό Kotlin으둜 진행쀑이기 λ•Œλ¬Έμ— μŠ€ν”„λ§κ³Ό 코틀린을 μ‚¬μš©ν•˜μ—¬ 예제 μ½”λ“œλ₯Ό μž‘μ„±ν–ˆμ§€λ§Œ κ°„λ‹¨νžˆ ν…ŒμŠ€νŠΈν•˜λŠ” μ½”λ“œμ΄κΈ° λ•Œλ¬Έμ— μžλ°”λ‘œ λ³€ν™˜ν•˜μ—¬ μ‚¬μš©ν•˜λ„ 무관할 λ“― ν•©λ‹ˆλ‹€.

(runCatching의 경우 Javaμ—μ„œμ˜ try-catch κ΅¬λ¬Έμž…λ‹ˆλ‹€.)

 

token, defaultChannel의 경우 μœ„μ—μ„œ μ„€μ •ν•œ Bot Token(OAuth Token)κ³Ό channel id 값을 μ„€μ •ν•΄μ£Όλ©΄ λ©λ‹ˆλ‹€.

 

sendMessage() λ©”μ†Œλ“œμ˜ 경우 2개의 λ©”μ†Œλ“œλ₯Ό λ§Œλ“€μ—ˆλŠ”λ°μš”, ν˜„μž¬λŠ” μ•Œλ¦Όμ„ 받을 채널이 ν•œκ°œλ§Œ μ‘΄μž¬ν•˜μ§€λ§Œ, μΆ”ν›„ 채널이 μΆ”κ°€λœλ‹€λ©΄ 직접 channel의 idλ₯Ό νŒŒλΌλ―Έν„°λ‘œ λ°›κΈ° μœ„ν•΄ μΆ”κ°€μ μœΌλ‘œ λ§Œλ“€μ—ˆμŠ΅λ‹ˆλ‹€.

 

λ˜ν•œ SlackServiceλ₯Ό μΈν„°νŽ˜μ΄μŠ€λ‘œ λ§Œλ“€κ³  이λ₯Ό κ΅¬ν˜„ν•˜λ„λ‘ SlackServiceImpl 클래슀λ₯Ό μƒμ„±ν•΄μ£Όμ—ˆλŠ”λ°μš”, μ΄λŠ” ν”„λ‘œμ νŠΈλ₯Ό μš΄μ˜μ€‘μΈ μ„œλ²„μ—μ„œ μ™ΈλΆ€ ν˜ΈμΆœμ„ ν•  λ•Œ ν”„λ‘μ‹œ μ„œλ²„ 등을 톡해 κ²½μœ ν• λ•Œ μΆ”κ°€μ μœΌλ‘œ κ΅¬ν˜„ν•˜μ—¬ μ‚¬μš©ν•  수 μžˆλ„λ‘ μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ‚¬μš©ν–ˆμŠ΅λ‹ˆλ‹€.

 

λ§ˆμ§€λ§‰μœΌλ‘œ showSlackInfo() λ©”μ†Œλ“œμ˜ 경우 sendMessage() λ©”μ†Œλ“œμ—μ„œ μ‚¬μš©λ  μŠ¬λž™ μ±„λ„μ˜ 정보λ₯Ό 얻을 수 μžˆμŠ΅λ‹ˆλ‹€.

(μœ„μ—μ„œ conversations.list μ—μ„œ ν™•μΈν•˜λŠ” 것과 λ™μΌν•©λ‹ˆλ‹€.)

 

μ‹€μ œ μœ„ sendMessage() λ©”μ†Œλ“œμ— text 메세지λ₯Ό 인자둜 μ „λ‹¬ν•΄μ„œ ν…ŒμŠ€νŠΈν•΄λ³΄λ©΄ μœ„μ™€ 같이 μŠ¬λž™μ— μ•Œλ¦Όμ΄ μ˜€λŠ”κ²ƒμ„ 확인할 수 μžˆμŠ΅λ‹ˆλ‹€.

 

 

정리

μ΄μƒμœΌλ‘œ Slack Apiλ₯Ό 톡해 μŠ¬λž™ 채널에 λ©”μ‹œμ§€λ₯Ό λ³΄λ‚΄λŠ” 방법에 λŒ€ν•΄ μ•Œμ•„λ³΄μ•˜μŠ΅λ‹ˆλ‹€.

μŠ¬λž™μ€ ꡉμž₯히 λ‹€μ–‘ν•œ μ„œλΉ„μŠ€μ™€μ˜ 연동이 κ°€λŠ₯ν•˜κΈ° λ•Œλ¬Έμ— λŒ€λΆ€λΆ„μ˜ μ•Œλ¦Όμ„ μŠ¬λž™μ„ 톡해 λ°›κ³  μžˆλŠ”λ°μš”, μ΄λŸ¬ν•œ μ•Œλ¦Όμ€ ν”„λ‘œμ νŠΈ μš΄μ˜μ— μžˆμ–΄ 거의 ν•„μˆ˜μ μΈ 뢀뢄이라고 μƒκ°ν•©λ‹ˆλ‹€.

 

ν•˜μ§€λ§Œ, λ„ˆλ¬΄λ‚˜ λ§Žμ€ μ„œλΉ„μŠ€μ— μ•Œλ¦Ό 섀정을 ν•  경우 이 λ˜ν•œ 관리 ν¬μ΄νŠΈκ°€ λ§Žμ•„μ§€λŠ” κ²½μš°κ°€ 생길 수 있기 λ•Œλ¬Έμ—, μ„œλΉ„μŠ€κ°€ 컀진닀면 μ„œλΉ„μŠ€μ˜ 상황에 맞게 λ°˜λ“œμ‹œ ν•„μš”ν•œ μ•Œλ¦Όλ§Œ μ„€μ •ν•˜μ—¬ 받을 수 μžˆλ„λ‘ ν•˜λŠ”κ²ƒμ΄ 쒋을 것 κ°™μŠ΅λ‹ˆλ‹€ πŸ˜ƒ

 

λ°˜μ‘ν˜•

'Kotlin' μΉ΄ν…Œκ³ λ¦¬μ˜ λ‹€λ₯Έ κΈ€

[Kotlin] - Class(클래슀)  (0) 2021.10.17

λŒ“κΈ€