slackapi / bolt-js

A framework to build Slack apps using JavaScript
https://tools.slack.dev/bolt-js/
MIT License
2.74k stars 393 forks source link

feat: Add request and respond object to context #545

Open seawatts opened 4 years ago

seawatts commented 4 years ago

I am trying to use the express receiver with adding my own middleware to the router. During that time I add things like request id as well as a scoped typedi container. These two things would be nice to be able to access on the context object that gets passed through to the bolt action and events middleware

seawatts commented 4 years ago

Any progress here?

aoberoi commented 4 years ago

Hey @seawatts, thanks for your patience. We've been thinking quite a bit about the problem you've presented here along with others that we felt were related. We've come up with a plan to address them in #670.

We'd appreciate feedback on whether or not this direction would serve your need. For the request ID, this is how I think it would work: your app would use the HTTPReceiver but instead of starting the built-in server, you'd use it as a request listener. You'd initialize express.App (or any other framework you choose) in your app, and use a middleware that puts a unique request ID into the HTTP headers (or some other pre-determined part of the req object). Then your Bolt listeners would find that data within the context. Here's some pseudo-code:

const express = require('express');
const { App, HTTPReceiver } = require('@slack/bolt');
const { v4: uuidv4 } = require('uuid');

// Initialize express app
const app = express();

// Add a requestId middleware
app.use((req, res, next) => {
  req.headers['X-Request-Id'] = uuidv4();
  next();
});

// Initialize Bolt app and receiver
const receiver = new HTTPReceiver({ signingSecret: '', ... });
const boltApp = new App({ token: '', receiver, ... });

// Connect express app to Bolt receiver
app.use('/slack/events', receiver.requestListener);

// Start the express app
app.listen(process.env.PORT || 3000);

As for a scoped typedi container, I'd recommend a pattern where the scope isn't request-specific. Instead the dependencies are injected at application boot in an outer scope. If you'd like an example of this, let me know.

aoberoi commented 4 years ago

If you think the linked issue solves for your need, let us know. We can then move forward with labeling this issue duplicate and consolidating conversation and updates there.

seawatts commented 3 years ago

@aoberoi thanks for sharing that example. I have actually forked this repo and did something very similar, more of a hack for short term fix though.

As far as the typedi dependencies this is a pattern that is recommended by TypeGraphQL here: https://github.com/MichalLytek/type-graphql/blob/master/docs/dependency-injection.md#scoped-containers

Which I actually use heavily within my application for creating scoped loggers that automatically attach things like the request id and user id onto each log request.

Let me know if that makes sense.

seawatts commented 3 years ago

@aoberoi any updates here?

filmaj commented 1 month ago

I believe request and responses are available in the HTTPReceiver, though confusingly they hang off of the ack object propagated to listeners. The same could be done in the AWSReceiver and in the ExpressReceiver.

It would be trivial to expose the request and response objects directly as listener arguments, so that's something that could be done. I don't think this would require a new major version, could be a minor update.