kotlinspring-bootslackbotsintegraciones
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
plugins {
kotlin("jvm") version "1.9.22"
id("org.springframework.boot") version "3.2.2"
id("io.spring.dependency-management") version "1.1.4"
kotlin("plugin.spring") version "1.9.22"
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("com.slack.api:bolt:1.36.1")
implementation("com.slack.api:bolt-servlet:1.36.1")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
}Luego, define las variables de entorno en
application.yml. Nunca escribas los tokens directamente en el código fuente:yaml
slack:
bot-token: ${SLACK_BOT_TOKEN}
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
@Configuration
class SlackConfig(
@Value("${'$'}{slack.bot-token}") private val botToken: String,
@Value("${'$'}{slack.signing-secret}") private val signingSecret: String
) {
@Bean
fun appConfig(): AppConfig {
val config = AppConfig()
config.singleTeamBotToken = botToken
config.signingSecret = signingSecret
return config
}
@Bean
fun slackApp(appConfig: AppConfig): App {
val app = App(appConfig)
// Registrar handlers aquí
registerCommands(app)
registerEvents(app)
return app
}
@Bean
fun slackServlet(app: App): SlackAppServlet = SlackAppServlet(app)
}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
@Configuration
class ServletConfig {
@Bean
fun slackServletRegistration(slackServlet: SlackAppServlet): ServletRegistrationBean<SlackAppServlet> {
return ServletRegistrationBean(slackServlet, "/slack/events")
}
}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
fun registerCommands(app: App) {
// /hello: responder con un saludo personalizado
app.command("/hello") { req, ctx ->
val userName = req.payload.userName
ctx.ack("Hola $userName! Soy tu bot escrito en Kotlin.")
}
// /ticket: crear un ticket simple
app.command("/ticket") { req, ctx ->
val text = req.payload.text
if (text.isNullOrBlank()) {
ctx.ack("Uso: /ticket [descripción del problema]")
} else {
// Aquí podrías guardar en base de datos, crear un issue en Jira, etc.
ctx.ack("Ticket creado: *$text*
Reportado por: <@${req.payload.userId}>")
}
}
}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
fun registerEvents(app: App) {
// Responder cuando mencionan al bot en un canal
app.event(AppMentionEvent::class.java) { event, ctx ->
val text = event.event.text
val channel = event.event.channel
val user = event.event.user
ctx.client().chatPostMessage { msg ->
msg.channel(channel)
.text("Hola <@$user>! Me mencionaste diciendo: "$text"")
}
ctx.ack()
}
// Escuchar mensajes directos al bot
app.event(MessageEvent::class.java) { event, ctx ->
if (event.event.channelType == "im") {
ctx.client().chatPostMessage { msg ->
msg.channel(event.event.channel)
.text("Recibí tu mensaje. Soy un bot, pero estoy escuchando.")
}
}
ctx.ack()
}
}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
app.command("/status") { req, ctx ->
ctx.ack { res ->
res.blocks {
section {
markdownText("*Estado del Sistema*")
}
divider()
section {
markdownText(":white_check_mark: *API Gateway* - Operativo")
}
section {
markdownText(":white_check_mark: *Base de datos* - Operativo")
}
section {
markdownText(":warning: *Cache Redis* - Latencia elevada (250ms)")
}
context {
markdownText("Última actualización: ${java.time.LocalDateTime.now()}")
}
}
}
}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
# Instalar ngrok (macOS con Homebrew)
brew install ngrok
# Exponer tu app local en el puerto 8080
ngrok 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.