Slack通知（Spring Boot）

# この記事は
`Spring Boot` + `Slack`通知を実装します。
具体的には、コントローラ層で受け取った`Json`をそのまま任意の`Slack`チャンネルへ飛ばします。

`Spring Boot`を使用していますが、言語は`Kotlin`ですのでご留意ください。

# 簡単な実験
とりあえず、リクエストを受け取って`Slack API`オブジェクトを生成する部分までを作成します。

```build.gradle.kts
// slack api dependency
implementation("com.slack.api:slack-api-client:1.23.0")

```

```SlackApiController.kt
@RestController
class SlackApiController(private val slackApiService: SlackApiService) {

    @PostMapping("/slack")
    fun sendSlack(@RequestBody request: SlackRequest): ResponseEntity<ApiTestResponse> {

        val response = slackApiService.sendMessage(request.message)
        return ResponseEntity.ok(response)
    }

    data class SlackRequest(
            val message: String
    )
}
```

```SlackApiService.kt
@Service
class SlackApiService {

    fun sendMessage(message: String): ApiTestResponse? {
        val slack = Slack.getInstance()
        return slack.methods().apiTest { it.foo(message) }
    }
}
```

上記のクラスが作成できたら、とりあえず試してみます。
`Slack API`の`ApiTestResponse`を返却しているため、色々な属性がレスポンスに含まれますが、動作確認としてはこれで良しとします。
```
$ curl localhost:8083/slack -X POST -d '{"message": "hello!"}' -H "Content-Type: application/json"

{"ok":true,"args":{"foo":"hello!","error":null},"warning":null,"error":null,"needed":null,"provided":null,"httpResponseHeaders":{"date":["Mon, 04 Jul 2022 02:05:37 GMT"],"server":["Apache"],"expires":["Mon, 26 Jul 1997 05:00:00 GMT"],"x-envoy-upstream-service-time":["156"],"vary":["Accept-Encoding"],"access-control-allow-headers":["slack-route, x-slack-version-ts, x-b3-traceid, x-b3-spanid, x-b3-parentspanid, x-b3-sampled, x-b3-flags"],"x-slack-req-id":["11c1bddbeb3054aed5e929db1049db0a"],"x-backend":["main_normal main_bedrock_normal_with_overflow main_canary_with_overflow main_bedrock_canary_with_overflow main_control_with_overflow main_bedrock_control_with_overflow"],"via":["envoy-www-iad-7wm4, envoy-edge-nrt-50b3"],"referrer-policy":["no-referrer"],"x-powered-by":["HHVM/4.153.1"],"content-type":["application/json; charset=utf-8"],"cache-control":["private, no-cache, no-store, must-revalidate"],"x-edge-backend":["envoy-www"],"x-slack-edge-shared-secret-outcome":["no-match"],"x-slack-backend":["r"],"pragma":["no-cache"],"strict-transport-security":["max-age=31536000; includeSubDomains; preload"],"access-control-expose-headers":["x-slack-req-id, retry-after"],"access-control-allow-origin":["*"],"x-content-type-options":["nosniff"],"x-xss-protection":["0"],"x-robots-tag":["noindex,nofollow"],"x-slack-shared-secret-outcome":["no-match"],"x-server":["slack-www-hhvm-main-iad-ik1w"]}}% 
```

# 実際にメッセージを送付するまで
[APIクライアントの基本](https://slack.dev/java-slack-sdk/guides/ja/web-api-basics)を参考にすると良いです。
また、トークンの生成方法については[こちらの記事](https://zenn.dev/kou_pg_0131/articles/slack-api-post-message)を参考にしてください。
トークンの生成およびSlackのアプリ設定が終わったら、以下のようにソースを修正します。
チャンネル（下記コードで言うと`#random`）については、IDを使用する方が良いそうなので、[こちら](https://qiita.com/unsoluble_sugar/items/603e51106d9632f3ea4f)を参考にチャンネルIDを取得してください。

```SlackApiService.kt
@Service
class SlackApiService {

    fun sendMessage(message: String): ChatPostMessageResponse? {
        // トークンはソースコードにベタ書きするのは避けた方が良いがとりあえず
        val token = "xoxb-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
        val slack = Slack.getInstance()
        val methods = slack.methods(token)
        val request = ChatPostMessageRequest.builder()
                .channel("#random") // チャンネルにはIDを指定すること
                .text(message)
                .build()
        return methods.chatPostMessage(request)
    }
}
```
修正が終わったら、先ほどと同じ`curl`コマンドを実行することでメッセージが該当チャンネルに送信されます。

# 終わりに
簡単ではありますが、`Slack` + `Spring Boot`を用いたアプリケーションの実装に役立てていただければと思います。

# 参考

https://slack.dev/java-slack-sdk/guides/ja/web-api-basics