Fecha de publicación: 2023-11-30
Slack Bolt es el framework oficial de Slack para construir aplicaciones: bots, integraciones y workflows. Aunque la documentación oficial se enfoca principalmente en JavaScript y Python, el SDK de Bolt para JVM funciona perfectamente con Kotlin. En este tutorial construiremos un bot funcional paso a paso, integrando Bolt con Spring Boot.
Al finalizar tendrás un bot capaz de:
- Responder a slash commands personalizados
- Escuchar menciones y mensajes directos
- Enviar mensajes con Block Kit (formato enriquecido)
- Desplegarse en producción con Spring Boot
Paso 1: Crear la app en Slack
Antes de escribir una sola línea de código, necesitas registrar tu bot en Slack:
- Ve a
api.slack.com/appsy haz clic en Create New App, luego selecciona From Scratch. - Asigna un nombre a tu app y selecciona el workspace donde la instalarás.
- En OAuth & Permissions, agrega los siguientes Bot Token Scopes:
chat:write: para que el bot pueda enviar mensajescommands: para registrar slash commandsapp_mentions:read: para escuchar cuando mencionan al botim:history: para leer mensajes directos
- Instala la app en tu workspace haciendo clic en Install to Workspace.
- Guarda el Bot Token (comienza con
xoxb-) y el Signing Secret que encontrarás en Basic Information. Los necesitarás para configurar tu app.
Paso 2: Configurar el proyecto Kotlin
Configura tu
build.gradle.kts con las dependencias de Spring Boot y Bolt para JVM:kotlin
1plugins {
2 kotlin("jvm") version "1.9.22"
3 id("org.springframework.boot") version "3.2.2"
4 id("io.spring.dependency-management") version "1.1.4"
5 kotlin("plugin.spring") version "1.9.22"
6}
7
8dependencies {
9 implementation("org.springframework.boot:spring-boot-starter-web")
10 implementation("com.slack.api:bolt:1.36.1")
11 implementation("com.slack.api:bolt-servlet:1.36.1")
12 implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
13}Luego, define las variables de entorno en
application.yml. Nunca escribas los tokens directamente en el código fuente:yaml
1slack:
2 bot-token: ${SLACK_BOT_TOKEN}
3 signing-secret: ${SLACK_SIGNING_SECRET}Paso 3: Configurar Bolt con Spring Boot
Crea una clase de configuración que inicialice el
AppConfig, el App de Bolt y el servlet que recibirá los eventos de Slack:kotlin
1@Configuration
2class SlackConfig(
3 @Value("${'$'}{slack.bot-token}") private val botToken: String,
4 @Value("${'$'}{slack.signing-secret}") private val signingSecret: String
5) {
6 @Bean
7 fun appConfig(): AppConfig {
8 val config = AppConfig()
9 config.singleTeamBotToken = botToken
10 config.signingSecret = signingSecret
11 return config
12 }
13
14 @Bean
15 fun slackApp(appConfig: AppConfig): App {
16 val app = App(appConfig)
17
18 // Registrar handlers aquí
19 registerCommands(app)
20 registerEvents(app)
21
22 return app
23 }
24
25 @Bean
26 fun slackServlet(app: App): SlackAppServlet = SlackAppServlet(app)
27}El servlet de Bolt necesita estar mapeado a una ruta específica. Slack enviará todos sus eventos HTTP a esa ruta. Registra el servlet en Spring con un
ServletRegistrationBean:kotlin
1@Configuration
2class ServletConfig {
3 @Bean
4 fun slackServletRegistration(slackServlet: SlackAppServlet): ServletRegistrationBean<SlackAppServlet> {
5 return ServletRegistrationBean(slackServlet, "/slack/events")
6 }
7}Paso 4: Slash Commands
Los slash commands son comandos que los usuarios escriben en Slack comenzando con
/. Bolt los registra con app.command(). El handler recibe el payload de la solicitud y debe responder con ctx.ack():kotlin
1fun registerCommands(app: App) {
2 // /hello: responder con un saludo personalizado
3 app.command("/hello") { req, ctx ->
4 val userName = req.payload.userName
5 ctx.ack("Hola $userName! Soy tu bot escrito en Kotlin.")
6 }
7
8 // /ticket: crear un ticket simple
9 app.command("/ticket") { req, ctx ->
10 val text = req.payload.text
11 if (text.isNullOrBlank()) {
12 ctx.ack("Uso: /ticket [descripción del problema]")
13 } else {
14 // Aquí podrías guardar en base de datos, crear un issue en Jira, etc.
15 ctx.ack("Ticket creado: *$text*
16Reportado por: <@${req.payload.userId}>")
17 }
18 }
19}Slack espera una respuesta en menos de 3 segundos. Si tu handler necesita más tiempo (por ejemplo, llamar a una API externa), usa
ctx.ackWithText() para responder de inmediato y luego envía un mensaje de seguimiento con ctx.respond() o ctx.client().Paso 5: Escuchar eventos (menciones y mensajes directos)
Para escuchar eventos como menciones al bot o mensajes directos, usa
app.event(). Asegúrate de haber habilitado Event Subscriptions en la consola de Slack y de haber suscrito los eventos correspondientes (app_mention y message.im):kotlin
1fun registerEvents(app: App) {
2 // Responder cuando mencionan al bot en un canal
3 app.event(AppMentionEvent::class.java) { event, ctx ->
4 val text = event.event.text
5 val channel = event.event.channel
6 val user = event.event.user
7
8 ctx.client().chatPostMessage { msg ->
9 msg.channel(channel)
10 .text("Hola <@$user>! Me mencionaste diciendo: "$text"")
11 }
12
13 ctx.ack()
14 }
15
16 // Escuchar mensajes directos al bot
17 app.event(MessageEvent::class.java) { event, ctx ->
18 if (event.event.channelType == "im") {
19 ctx.client().chatPostMessage { msg ->
20 msg.channel(event.event.channel)
21 .text("Recibí tu mensaje. Soy un bot, pero estoy escuchando.")
22 }
23 }
24 ctx.ack()
25 }
26}Paso 6: Mensajes con Block Kit
Block Kit es el sistema de componentes de Slack para construir mensajes con formato enriquecido: secciones, divisores, botones, imágenes y contexto. Es especialmente útil para dashboards o notificaciones de estado. El siguiente ejemplo muestra un comando
/status que reporta el estado de diferentes sistemas:kotlin
1app.command("/status") { req, ctx ->
2 ctx.ack { res ->
3 res.blocks {
4 section {
5 markdownText("*Estado del Sistema*")
6 }
7 divider()
8 section {
9 markdownText(":white_check_mark: *API Gateway* - Operativo")
10 }
11 section {
12 markdownText(":white_check_mark: *Base de datos* - Operativo")
13 }
14 section {
15 markdownText(":warning: *Cache Redis* - Latencia elevada (250ms)")
16 }
17 context {
18 markdownText("Última actualización: ${java.time.LocalDateTime.now()}")
19 }
20 }
21 }
22}El DSL de Block Kit en Kotlin es limpio y expresivo. Puedes construir bloques de manera declarativa sin manipular JSON directamente, lo que reduce errores y mejora la legibilidad.
Paso 7: Exponer con ngrok para desarrollo
Slack necesita una URL pública para enviar eventos HTTP a tu bot. Durante el desarrollo, puedes usar ngrok para crear un túnel desde internet hacia tu servidor local:
bash
1# Instalar ngrok (macOS con Homebrew)
2brew install ngrok
3
4# Exponer tu app local en el puerto 8080
5ngrok http 8080ngrok te mostrará una URL pública como
https://xxxx.ngrok.io. Copia esa URL y configúrala en dos lugares dentro de la consola de Slack:- Event Subscriptions → Request URL:
https://xxxx.ngrok.io/slack/events - Slash Commands → Request URL (en cada comando):
https://xxxx.ngrok.io/slack/events
Slack verificará la URL enviando un challenge. Bolt responde automáticamente a esta verificación, por lo que no necesitas escribir código adicional para ello.
Consideraciones para producción
Cuando lleves tu bot a producción, ten en cuenta los siguientes puntos:
- Variables de entorno: nunca escribas tokens en el código fuente. Usa variables de entorno o un gestor de secretos como AWS Secrets Manager o Vault.
- Rate limiting: Slack limita la cantidad de mensajes por segundo que puede enviar un bot. Implementa control de tasa en los handlers que generen muchos mensajes.
- Socket Mode: si no quieres exponer un endpoint HTTP público, activa Socket Mode en la consola de Slack. Tu bot se conecta mediante WebSocket y recibe los eventos sin necesidad de una URL pública.
- Logging: registra todos los eventos recibidos y las respuestas enviadas. Esto facilita el debugging cuando algo falle en producción.
- Procesamiento asíncrono: para tareas costosas (consultas pesadas, llamadas a APIs externas), considera delegar el trabajo a una cola como Kafka o SQS. Responde a Slack de inmediato y procesa en segundo plano.
Conclusión
Slack Bolt con Kotlin es una combinación sólida para automatizar flujos de trabajo internos. El SDK de Bolt para JVM es maduro y cubre los casos de uso más comunes: slash commands, eventos, mensajes enriquecidos con Block Kit e interacciones con botones. Con Spring Boot como base, tienes un bot listo para producción con muy poco esfuerzo de configuración.


