将Firebase onRequest()或Express app.use()用于Slack API

时间:2018-09-18 14:29:05

标签: firebase express google-cloud-functions middleware slack-api

目标

@slack/interactive-message软件包与firebase-functions一起使用以侦听和响应Slack消息和对话框。

问题

我不确定如何在Firebase中使用@slack/interactive-message侦听器。

1)我是否使用Firebase的functions.https.onRequest(),并且以某种方式req从Slack传递到slackInteractions.action()

OR

2)我是否使用app.use("/app", slackInteractions.expressMiddleware());slackInteractions.action()转到在哪里使用?

OR

3)还有别的吗?

代码

// Express
import express = require("express");
const app = express();
const cors = require("cors")({
  origin: "*"
});
app.use("*", cors);

// Firebase Functions SDK
import functions = require("firebase-functions");

const slackbotConfig = functions.config().slackbot;
const { createMessageAdapter } = require("@slack/interactive-messages");
const slackInteractions = createMessageAdapter(slackbotConfig.signing_secret);

app.use("/app", slackInteractions.expressMiddleware());

// Express route
app.post("/go", (req, res) => {
  console.log("Hello from Express!");
  res
    .status(200)
    .send("Hello from Express!")
    .end();
});

exports.app = functions.https.onRequest(app);

exports.helloWorld = functions.https.onRequest((_req, res) => {
  console.log("Hello from Firebase!");
  res
    .status(200)
    .send("Hello from Firebase!")
    .end();
});

tl; dr

我对Express和使用中间件的细节不熟悉。 @slack/interactive-message的示例显示...

slackInteractions.start(port).then(() => {
  console.log(`server listening on port ${port}`);
});

...并且与Firebase Cloud Functions无关。我不确定Firebase和@ slack / interactive-message

之间如何集成侦听器,请求和响应

1 个答案:

答案 0 :(得分:5)

@slack/interactive-messages的创建者

简而言之,您的解决方案编号2对我来说似乎是正确的。虽然我没有使用Firebase函数的经验,但是我对Express有了很好的理解,我将提供更多详细信息。

什么是快速中间件?

Express中间件是一种用于处理传入HTTP请求的函数的名称。所有中间件功能都可以在逐个请求的基础上选择预处理请求(通常通过向req参数添加属性),响应请求或对请求进行后处理(例如计算请求和响应之间的时间)。它可以完成任何一项或多项操作,具体取决于其要完成的工作。一个快速应用程序管理一堆中间件。您可以将其视为请求准备好响应之前可以执行的步骤的列表。该列表中的每个步骤都可以决定提供响应,以便对该请求甚至不进行下一步。

您的代码示例中的cors值是一个中间件函数。它应用了一些规则,这些规则涉及Firebase函数应从哪个来源接受请求。它将这些规则应用于传入的请求,当不允许源时,它将立即响应并返回错误。否则,它将允许该请求由堆栈中的下一个中间件处理。

您的示例中还有另一个中间件,那就是路由器。路由器只是一种中间件,它知道如何根据传入请求中的路径(URL的一部分)将应用程序拆分为单独的处理程序。每个Express app都带有一个内置路由器,您在示例中使用app.post("/go", () => {});行代码将处理程序附加到该路由器上。路由器通常是堆栈中的最后一个中间件。它们确实具有人们通常不会意识到的特殊功能。这些路线处理程序是什么?它们只是更多中间件功能。因此,总的来说,您可以将路由器视为一种中间件,可以帮助您根据请求的路径划分应用程序行为。

这对slackInteractions意味着什么?

您可以将代码中的slackInteractions对象看作是路由器,它始终处理该请求-它从不将请求传递到堆栈中的下一个中间件。关键区别在于,它不是通过请求路径来划分应用程序行为,而是使用Slack交互的各种属性来划分行为。您describe which properties exactly you care about by passing in constraints.action()方法。典型路由器和slackInteractions之间唯一的显着区别是,值本身不是快速中间件,您可以通过调用.expressMiddleware()方法来生成快速中间件。像这样拆分,以便它也可以在快速应用程序之外运行(那是您可以使用.start()方法的时候)。

放在一起

就像我说的那样,我没有Firebase函数的专门经验,但是我相信这是您应该从最低限度开始的,仅处理Slack交互的函数。

// Firebase Functions SDK
import functions = require("firebase-functions");
const slackbotConfig = functions.config().slackbot;

// Slack Interactive Messages Adapter
const { createMessageAdapter } = require("@slack/interactive-messages");
const slackInteractions = createMessageAdapter(slackbotConfig.signing_secret);

// Action handlers
slackInteractions.action('welcome_agree_button', (payload, respond) => {
  // `payload` is an object that describes the interaction
  console.log(`The user ${payload.user.name} in team ${payload.team.domain} pressed a button`);

  // Your app does some asynchronous work using information in the payload
  setTimeout(() => {
    respond({ text: 'Thanks for accepting the code of conduct for our workspace' });
  }, 0)

  // Before the work completes, return a message object that is the same as the original but with
  // the interactive elements removed.
  const reply = payload.original_message;
  delete reply.attachments[0].actions;
  return reply;
});

// Express
import express = require("express");
const app = express();
app.use("/", slackInteractions.expressMiddleware());

exports.slackActions = functions.https.onRequest(app);