-
Notifications
You must be signed in to change notification settings - Fork 384
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Integrating a Bolt app into another server or framework (upward modularity) #212
Comments
Any Progress on This issue? |
I would also be interested as a possible way to solve #283 |
is this related to |
Is there any update on this? I'm trying to implement it in my NestJS application but neither NestJS or Bolt allows me to pass an existing express instance. |
Same boat as @regniblod - trying to combine Nestjs and bolt. Any update on this? |
Hi folks! Integrating Bolt for JS into other HTTP servers/frameworks is something we're interested in making happen. Within the team, we've called this idea "upward modularity" since its about making Bolt fit inside a larger app. (It's probably not important but "downward modularity" would be about combining several parts of a Bolt app into one Bolt app). We want this to work in a generic way, so that Bolt can integrate not only into NestJS, but into nearly any web server/framework (Express, hapi, plain Node The way to move this topic forward would be with a proposal. If you have a specific idea for how you think this should work, please go ahead and write up a description. It doesn't need to be anything formal, just something to describe how you'd like to see the feature work. We can help suss out any questions that arise from that, and the community can help design a solution. PS. If you just want to hook into Bolt's underlying express app by adding a few custom routes, you can already do that, but we need to document that better. |
Meanwhile, this worked for me - Extract the express app from bolt and add nestjs middleware. import { App, ExpressReceiver } from '@slack/bolt';
import { AppMiddleware } from './nestj/app.middleware';
const receiver = new ExpressReceiver({ signingSecret: configuration.slackSigningSecret });
const app = new App({
receiver,
token: configuration.slackAccessToken,
signingSecret: configuration.slackSigningSecret,
});
receiver.app.use((req, res, next) => {
const nest = new AppMiddleware(app).use(req, res, next);
nest.then(() => {
next();
}).catch(err => {
next();
});
});
// Start your app
const port = configuration.port || 3000;
await app.start(port);
console.log("⚡️ Bolt app is running! on port " + port); https://slack.dev/bolt-js/concepts#custom-routes I followed this SO answer to implement the NestJS middleware.
import { Injectable, NestMiddleware } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { ExpressAdapter } from '@nestjs/platform-express';
import { AppModule } from './app.module';
const bootstrap = async (express: Express.Application) => {
const app = await NestFactory.create(AppModule, new ExpressAdapter(express));
await app.init();
return app;
}
@Injectable()
export class AppMiddleware implements NestMiddleware {
constructor(private expressInstance: Express.Application) {}
use(req: any, res: any, next: () => void) {
console.log('In Nest middleware');
return bootstrap(this.expressInstance);
}
} |
Hi! const { App } = require('@slack/bolt');
const express = require('express')
const expressApp = express()
const boltApp = new App({
token: configuration.slackAccessToken,
signingSecret: configuration.slackSigningSecret,
});
const boltMiddleware = boltApp.getMiddleware();
expressApp.use('/bolt', boltMiddleware); |
Works fine for me: const { App } = require('@slack/bolt');
const express = require('express');
const app = express();
const boltApp = new App({
signingSecret: config.slackApp.signingSecret,
token: config.slackApp.token,
endpoints = '/'
});
app.use('/slack/events', boltApp.receiver.router); // works also with boltApp.receiver.app You can add a path in the |
To cover the Hapi framework v.17+ you can jerry-rig a solution by registering Bolt's provided Express Receiver as a plugin using the hecks package. It's not the most elegant solution but I needed something that worked quickly... Hope it helps someone! const Hapi = require('@hapi/hapi');
const Hecks = require('hecks');
const { App, ExpressReceiver } = require('@slack/bolt');
// INIT BOLT APP
const Receiver = new ExpressReceiver({ signingSecret: SLACK_SIGNING_SECRET });
const BoltApp = new App({
token: SLACK_BOT_TOKEN,
signingSecret: SLACK_SIGNING_SECRET,
receiver: Receiver
});
// INIT HAPI SERVER
const init = async () => {
const server = Hapi.server({
port: 3000,
host: 'localhost'
});
await server.register([Hecks.toPlugin(BoltApp.receiver.app, 'my-bolt-app')]);
server.route({
method: '*',
path: '/slack/events',
handler: {
express: BoltApp.receiver.app
}
});
await server.start();
console.log('Server running on %s', server.info.uri);
};
process.on('unhandledRejection', (err) => {
console.log(err);
process.exit(1);
});
init(); |
Hi there!! Thank you for all of your advices. import { App, ExpressReceiver } from '@slack/bolt';
export const createApp = (appName: string) => {
const signingSecret = ...;
const token = ...;
const receiver = new ExpressReceiver({
signingSecret,
endpoints: {
events: `/${appName}/slack/events`,
},
});
const app = new App({
token,
receiver,
});
return { app, receiver };
}; one slack app: import { createApp } from './createApp';
const { app, receiver } = createApp('app-a');
app.message('hello app-a', async ({ body, say }) => {
await say(`Hey there, I'm app-a`);
});
export { receiver };
import express from 'express';
import { receiver as appA } from './app-a';
import { receiver as appB } from './app-b';
const app = express();
// you can add more apps
app.use(appA.router); // App A's Event Subscription > Request URL is https://yourserver/app-a/slack/events
app.use(appB.router); // App B's Event Subscription > Request URL is https://yourserver/app-b/slack/events
app.listen(3030); |
Thanks @tell-y works like a charm 🙏 |
hi there! context: @slack/bolt 3.4.0 + typescript with a lot of inspiration from this thread and @tell-y code, I still can't get slack to connect to my public server; the ultimate objective is to get slashCommands working with bolt as it did using a custom solution. maybe anyone of you see something obvious that is missing or mis-configured... ? status:
main code bits: file
file
|
@bertho-zero @cShingleton @aoberoi When I try the approach with
Does anyone have a working example of integrating Bolt into an existing express app? I'm struggling to find a clear migration example from the deprecated slack packages. |
@captDaylight I had the same issue; the solution is in above code |
Thanks @jyb247, when I consolidate your comment with another one from above I get something like this: import { App, ExpressReceiver } from '@slack/bolt';
import express from 'express';
const app = express();
const receiver = new ExpressReceiver({ signingSecret: process.env.SLACK_SIGNING_SECRET });
const boltApp = new App({
token: process.env.SLACK_BOT_TOKEN,
signingSecret: process.env.SLACK_SIGNING_SECRET,
receiver,
});
app.use('/', receiver.router); EDIT: Removed error message, resolved issue |
@captDaylight how does your package.json look like? (list only lines with |
@jyb247 disregard, thanks for the help! |
@captDaylight so I guess all is working on your side, incl events and slashCommands ? if so, could you share your Slack App Configuration (as to find a solution to my original solution) |
@jyb247 I just have the basics done, but I'll post an update early next week once I've made some more progress. |
Hey guys, we have attempted to integrate Bolt with Express. Since the slack team works at bolt level, we thought of offering a higher-level abstraction, leveraging Express with simple structure and brought in Bolt. The idea is to build a starter kit for building Slack (and Teams app) apps without worrying about low-level details. This is in the draft stage, ideas & suggestions are welcome! |
@jyb247 did you ever get a solution for the
|
@alexbaileyuk @jyb247 |
Did you figure it out with events and commands? |
@8YOne that solved it for me thanks! |
Is there a simple working example for this scenario? |
I suspect this will resolve this issue ? #868 |
I'm currently working on a rewrite from const app = express()
const boltReceiver = new ExpressReceiver({signingSecret, endpoints: '/'})
const boltApp = new App({token: botToken, receiver: boltReceiver})
boltApp.event('member_joined_channel', ({event}) => handleMemberJoined(event))
boltApp.event('message', ({event}) => handleMessage(event))
app.use(`/events/${botSubpath}`, boltReceiver.router) Simple as that. Thanks again. |
I'm currently doing something like this except in typescript, it complains that |
@billyvg Hi, it was mentioned later in the thread that this is indeed an issue. Please check my last post for a clean solution in typescript. |
@rtrembecky Thank you for coming back and updating your code examples! I am trying to implement this, but I keep getting a type error on the boltReceiver.router passed to app.use as the second param.
As far as I can tell, what I have is functionally the same as your code snippet and I'm left scratching my head. Have you noticed/had to work around this type error at all? I'm using |
@zaclittleberry Hi, I have |
@rtrembecky thanks for the reply! I'm not sure, either. It doesn't have a type error if I use In case it is helpful to anyone else: I had to resolve a separate issue after that though, where placing the |
👋 It looks like this issue has been open for 30 days with no activity. We'll mark this as stale for now, and wait 10 days for an update or for further comment before closing this issue out. If you think this issue needs to be prioritized, please comment to get the thread going again! Maintainers also review issues marked as stale on a regular basis and comment or adjust status if the issue needs to be reprioritized. |
As this issue has been inactive for more than one month, we will be closing it. Thank you to all the participants! If you would like to raise a related issue, please create a new issue which includes your specific details and references this issue number. |
I wanted to show a pattern that worked for me in nestjs while I was working on solving this. Hopefully this helps. I define a slack service:
And then in my main.js where I'm initializing the app module, I reference it like this:
|
has anyone found another solution to the problem stated by @zaclittleberry? Specifically, the broken stream/body reading if Update: replacing Update 2: nope, it did not. Update 3:
|
Updating the above. What I have found but cannot fully understand yet is the different between the readableStates:
Update 1: Update 2:
I hope this helps more people struggling with this. |
Thanks so much for this, it was a lifesaver! By the way, if anyone else is using this as well and is wondering why |
Did anyone manage to implement an installation store with this solution? It seems when you do, it doesn't inject the token into requests. |
@n6rayan Any updates since you had this issue? I'm facing exactly that with my NestJS and Bolt-js set-up via UPD: have managed to sort it out. It's essential to maintain the same data structure in production installationStore that is used in FileInstallationStore. Also, it's important to clean up older installations from DB, as some can be duplicates with invalid token. |
I would like to use bolt as an express middleware similar to how the @slack/events-api work.
app.use('/slack/events', slackEvents.expressMiddleware());
Is there an equivalent in bolt? Thanks
The text was updated successfully, but these errors were encountered: