slackend

5.0.0 • Public • Published

Asynchronous Slackbot

npm test coverage maintainability

A simple, asynchronous back end for your Slack app.

The app intentionally does very little: it is essentially middleware for ExpressJS that accepts an incoming request, verifies its origin, and passes the request to a user-provided callback, where the payload is sent to a queue/trigger for asynchronous processing.

Endpoints are provided for:

  • GET /health check to verify the service is running
  • GET /install begin the process of installing your app to a workspace
  • GET /oauth completes the OAuth2 workflow
  • GET /oauth/v2 completes the OAuth2 workflow (v2)
  • POST /callbacks publishes interactive messages
  • POST /events publishes events from the Events API
  • POST /slash/:cmd publishes slash commands

In production it is expected that users will attach their own publishing functions to connect to a messaging service like Amazon EventBridge, or Google Pub/Sub.

Advantages

  • Separates the concerns of responding to incoming requests and the logic to handle them.
    • Handlers can be added/removed independently of this app; deploy once and forget.
    • Requests can be published to any platform.
    • Handlers can be written in any language supported by the topic trigger.
  • Designed to work within serverless frameworks, such as AWS Lambda or Google Cloud Functions.
  • Authenticates requests using Slack's signing secrets so you'll know that events published to internal triggers/queues are verified.

Drawbacks

  • Slack has a strict 3-second lifetime for many API operations, so it is critical that your asynchronous tasks complete quickly. Cold start times of some serverless computing platforms may be prohibitively slow. (Note: this concern can be effectively eliminated on most platforms by configuring your serverless functions for speed)

Processing Events

In very simple terms, all events are processed by transforming the request payload to a JSON object and assigning it to the express local res.locals.slack.

It is left to the user to handle further transformation and publishing of the event, however the aws module provides an implementation that publishes the events to EventBridge.

Here is an example configuration that simply responds to incoming requests with the processed payload:

const express = require("express");
const slackend = require("slackend");
const app = express();
app.use(slackend(), (req, res) => res.json(res.locals.slack));
app.listen(3000);

Serverless Deployment

AWS

Deploying a version of this app to Amazon Web Services (AWS) serverless offerings might take the above shape, where incoming requests from Slack to your app are handled as follows:

API Gateway receives and routes all requests to a single Lambda function integration.

On cold starts, the Lambda function pulls its Slack tokens/secrets from its encrypted SecretsManager secret, starts a proxy express server, and publishes the request to an EventBridge bus.

On warm starts the environment and server are cached and the request is published to EventBridge without needing to re-fetch the app secrets.

Once the request is published, the API sends a 204 NO CONTENT response back to Slack.

Using this method, each feature of your app can be added one-by-one independently of the API and is highly scalable.

NodeJS Usage

At its core, slackend is middleware for ExpressJS with several routes predefined for handling Slack messages. None of the routes are configured to respond to the request. This is done deliberately so users can customize the behavior of the app.

The Slack message and an inferred topic name are stored in the res.locals object and can be used to publish the request to your preferred messaging/queueing service.

Here is an example usage that simply logs the request to the console:

const slackend = require("slackend");

// Create express app
const app = slackend({
  client_id: process.env.SLACK_CLIENT_ID,
  client_secret: process.env.SLACK_CLIENT_SECRET,
  oauth_error_uri: process.env.SLACK_OAUTH_ERROR_URI,
  oauth_redirect_uri: process.env.SLACK_OAUTH_REDIRECT_URI,
  oauth_success_uri: process.env.SLACK_OAUTH_SUCCESS_URI,
  signing_secret: process.env.SLACK_SIGNING_SECRET,
  signing_version: process.env.SLACK_SIGNING_VERSION,
  token: process.env.SLACK_TOKEN,
});

// You *must* add a callback that responds to the request
app.use((req, res) => {
  console.log(res.locals);
  res.json({ ok: true });
});

WARNING — All of the configuration options to slackend() are optional, but omitting the signing_secret will disable the verification step where received requests are confirmed as originating from Slack. Disabling verification can also be done by setting the environmental variable DISABLE_VERIFICATION=1.

Local Development

Run a local instance of your slack app by cloning this repository, configuring settings, installing dependencies, and starting the express server.

Configure settings by copying .env.example to .env and adding your keys/settings.

cp .env.example .env

Install dependencies using npm or docker-compose:

npm install

Start the server:

npm start

Send a sample request:

# Callback
curl --request POST \
  --data 'payload=%7B%22callback_id%22%3A%22fizz%22%7D' \
  --url 'http://localhost:3000/callbacks'

# Event
curl --request POST \
  --header 'Content-Type: application/json' \
  --data '{"type": "event_callback", "event": {"type": "team_join"}}' \
  --url 'http://localhost:3000/events'

# Slash command
curl --request POST \
  --data 'fizz=buzz' \
  --url 'http://localhost:3000/slash/fizz'

AWS

A module is provided to deploy to Lambda using SecretsManager to store the Slack secrets.

Example Lambda handler:

const slackend = require("slackend/aws");
module.exports = slackend();

Deploy with Terraform

Deploy directly to AWS using terraform and the slackbot + slackbot-secrets modules:

resource "aws_apigatewayv2_api" "slackbot_api" {
  name          = "my-slack-api"
  protocol_type = "HTTP"
  #
}

module "slackbot" {
  source  = "amancevice/slackbot/aws"
  version = "~> 20.1"

  http_api_execution_arn = aws_apigatewayv2_api.http_api.execution_arn
  http_api_id            = aws_apigatewayv2_api.http_api.id
  lambda_function_name   = "my-function-name"
  role_name              = "my-role-name"
  secret_name            = module.slackbot_secrets.secret.name
  topic_name             = "my-topic-name"

  #
}

module "slackbot_secrets" {
  source               = "amancevice/slackbot-secrets/aws"
  kms_key_alias        = "alias/slack/your-kms-key-alias"
  secret_name          = "slack/your-secret-name"
  slack_bot_token      = "your-bot-token"
  slack_client_id      = "your-client-id"
  slack_client_secret  = "your-client-secret"
  slack_signing_secret = "your-signing-secret"
  slack_user_token     = "your-user-token"

  // Optional additional secrets
  secrets = { FIZZ = "buzz" }
}

Dependencies (4)

Dev Dependencies (6)

Package Sidebar

Install

npm i slackend

Weekly Downloads

1

Version

5.0.0

License

MIT

Unpacked Size

22 kB

Total Files

6

Last publish

Collaborators

  • amancevice