在 webhook 触发的函数 运行 之后,如何将信息发送回前端?

How to send information back to the Front end, AFTER functions triggered by a webhook are ran?

我正在使用 Plaid API 从注册用户那里收集交易数据。本质上,Plaid 需要检索对我们的 webhook 端点的更新,以便让服务器知道何时可以提取数据。当所需的代码从 Plaid 发送到该端点时,我们将知道交易数据已准备好检索,我们的后端将开始将其插入到我们的数据库中。

我们 运行 遇到的问题是如何将该数据发送到前端。由于我们仅在数据准备好从 webhook 端点上的 Plaid 中提取时才会收到警报,因此任何 res.send 都将转到 Plaid。如果我们有另一个端点来获取新插入的数据,用户将能够在 Webhook 操作发生之前点击那个端点。

我们有点卡住了。我们可以让 webhook 触发我们需要触发的操作,但是在用户被触发后将其发送回用户是另一个问题。有没有办法让我们的第三个端点在第二个端点完成后再将数据发送回前端?

这是 enpoint 1,它触发 Plaid 将他们的 webhook 发送到 webhook 端点。

router.post('/token_exchange', publicTokenExists, async (req, res) => {
  const {publicToken} = req.body;
  const {userid} = req.body;

  try {
    const {access_token} = await client.exchangePublicToken(publicToken);

    const Accessid = await qs.add_A_Token(access_token, userid);

    const {item} = await client.getItem(access_token);

    const Itemid = await qs.add_An_Item(item.item_id, userid);

    res.status(201).json({
      accessCreated: Accessid,
      ItemCreated:Itemid
    });
  } catch (err) {
    console.log('access', err);
  }
});

这是端点 2,webhook 端点。 First Plaid 发送一个 post 请求,其中包含一个我们忽略的对象,因为 webhook_code 不是我们想要对 运行 执行操作的对象。第二个通过了下面的条件

router.post('/webhook', async (req,res)=>{
  const body = req.body;
  console.log("THE WEBHOOK BRUH",body)

  if(body.webhook_code==="HISTORICAL TRANSACTIONS"){
    const A_token = await  qs.GetAccessTokenThatsConnectedTo(body.item_id)

    const {transactions} = await client.getTransactions(A_token)

        const done = Promise.all(
        transactions.map(async trans => {
        const contents = await qs.insert_transactions(trans);
        return trans;
      }),
    );

  } 

这是端点 3,这是我们的 React 前端请求我们的数据库进行交易的地方。

router.post('/transactions',checkAccessToken, async (req,res)=>{

  console.log("the request body", req.body)

  const access = req.body.access

  try{

const {transactions} = await qs.getTransactionsDataBaseThatWeInsertedInFunctiontwo
(access,'2019-01-01','2019-01-30')

res.status(200).json({transactions})
  }catch(err){
console.log(err)
res.status(500).json({message:"error sending transactions"})
  }

})

所以我想我正在寻找任一解决方案:

是否可以在方法2完成后发送插入的交易数据?

是否可以让方法 3 等到方法 2 完成,我最初考虑将其作为中间件函数,但我认为这不会消除返回 Plaid 而不是反应的响应问题?

我认为如果您在 Webhook 被触发时尝试推送到客户端 - 您可以:

  1. 存储来自端点一的 res 对象(不确定如何将 Webhook 调用映射到初始请求)。触发 Webhook 后,查找 res 对象并关闭初始请求。这不太理想。如果 Webhook 在初始请求套接字关闭之前未能触发,或者如果您需要扩展应用程序 - 它不会扩展,因为您始终需要在引用打开的套接字的同一应用程序中调用 Webhook。

  2. 使用网络套接字。保持对您的客户端开放的持久连接并在 webhook 调用时推送通知。

Plaid API documentation points to a Plaid Pattern repo 作为处理事务 webhook 的代码示例。在示例中,他们使用 WebSockets (Socket.IO) 通知前端。

const handleTransactionsWebhook = async (requestBody, io) => {
  const {
    webhook_code: webhookCode,
    item_id: plaidItemId,
    new_transactions: newTransactions,
    ...
  } = requestBody;

  const serverLogAndEmitSocket = (additionalInfo, itemId) => {
    console.log(
      `WEBHOOK: TRANSACTIONS: ${webhookCode}: Plaid_item_id ${plaidItemId}: ${additionalInfo}`
    );
    // use websocket to notify the client that a webhook has been received and handled
    if (webhookCode) io.emit(webhookCode, { itemId });
  };

  switch (webhookCode) {
    ...
    case 'HISTORICAL_UPDATE': {
      // Fired when an Item's historical transaction pull is completed. Plaid fetches as much
      // data as is available from the financial institution.
      const startDate = moment().subtract(2, 'years').format('YYYY-MM-DD');
      const endDate = moment().format('YYYY-MM-DD');
      await handleTransactionsUpdate(plaidItemId, startDate, endDate);
      const { id: itemId } = await retrieveItemByPlaidItemId(plaidItemId);
      serverLogAndEmitSocket(`${newTransactions} transactions to add.`, itemId);
      break;
    }
    ...
  }
}
  useEffect(() => {
    socket.current = io(`localhost:${REACT_APP_SERVER_PORT}`);

    ...

    socket.current.on('HISTORICAL_UPDATE', ({ itemId } = {}) => {
      const msg = `New Webhook Event: Item ${itemId}: Historical Transactions Received`;
      console.log(msg);
      toast(msg);
      getTransactionsByItem(itemId, true);
    });