or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced-features.mdcore-application.mdindex.mdmiddleware.mdreceivers.mdrequest-verification.md

middleware.mddocs/

0

# Built-in Middleware

1

2

Slack Bolt provides built-in middleware functions for filtering events, matching patterns, and processing requests. These middleware functions help route requests to appropriate handlers and provide common functionality.

3

4

## Capabilities

5

6

### Event Filtering Middleware

7

8

Filter incoming requests to specific event types for focused request processing.

9

10

```typescript { .api }

11

/**

12

* Middleware that filters out any event that isn't an action

13

* Only allows interactive component actions to pass through

14

*/

15

const onlyActions: Middleware<AnyMiddlewareArgs>;

16

17

/**

18

* Middleware that filters out any event that isn't a command

19

* Only allows slash commands to pass through

20

*/

21

const onlyCommands: Middleware<AnyMiddlewareArgs>;

22

23

/**

24

* Middleware that filters out any event that isn't a Slack event

25

* Only allows Events API events to pass through

26

*/

27

const onlyEvents: Middleware<AnyMiddlewareArgs>;

28

29

/**

30

* Middleware that filters out any event that isn't an options request

31

* Only allows external select menu option requests to pass through

32

*/

33

const onlyOptions: Middleware<AnyMiddlewareArgs>;

34

35

/**

36

* Middleware that filters out any event that isn't a shortcut

37

* Only allows global and message shortcuts to pass through

38

*/

39

const onlyShortcuts: Middleware<AnyMiddlewareArgs>;

40

41

/**

42

* Middleware that filters out any event that isn't a view action

43

* Only allows modal view submissions and closures to pass through

44

*/

45

const onlyViewActions: Middleware<AnyMiddlewareArgs>;

46

```

47

48

### Utility Middleware

49

50

General-purpose middleware for common functionality and request processing.

51

52

```typescript { .api }

53

/**

54

* Middleware that automatically acknowledges requests

55

* Calls ack() immediately when the middleware is invoked

56

*/

57

const autoAcknowledge: Middleware<AnyMiddlewareArgs>;

58

59

/**

60

* Middleware that ignores events from the bot itself

61

* Filters out messages and events where the user is the bot

62

*/

63

const ignoreSelf: Middleware<AnyMiddlewareArgs>;

64

65

/**

66

* Middleware that only allows direct mentions of the bot

67

* Useful for filtering message events to only direct mentions

68

*/

69

const directMention: Middleware<SlackEventMiddlewareArgs<'message'>>;

70

```

71

72

**Usage Examples:**

73

74

```typescript

75

import { App, onlyActions, onlyCommands } from "@slack/bolt";

76

77

const app = new App({

78

token: process.env.SLACK_BOT_TOKEN,

79

signingSecret: process.env.SLACK_SIGNING_SECRET

80

});

81

82

// Use filtering middleware globally

83

app.use(onlyActions);

84

85

// Or use in specific listeners

86

app.use(onlyCommands, async ({ command, ack, respond }) => {

87

await ack();

88

await respond(`Received command: ${command.command}`);

89

});

90

```

91

92

### Pattern Matching Middleware

93

94

Match requests against specific patterns for conditional processing.

95

96

```typescript { .api }

97

/**

98

* Middleware that matches message text against a pattern

99

* @param pattern - String or RegExp pattern to match against message text

100

* @returns Middleware that only processes matching messages

101

*/

102

function matchMessage(

103

pattern: string | RegExp

104

): Middleware<SlackEventMiddlewareArgs<'message'>>;

105

106

/**

107

* Middleware that matches slash command names against a pattern

108

* @param pattern - String or RegExp pattern to match against command name

109

* @returns Middleware that only processes matching commands

110

*/

111

function matchCommandName(

112

pattern: string | RegExp

113

): Middleware<SlackCommandMiddlewareArgs>;

114

115

/**

116

* Middleware that matches event types against a pattern

117

* @param pattern - Event type pattern to match

118

* @returns Middleware that only processes matching event types

119

*/

120

function matchEventType(

121

pattern: EventTypePattern

122

): Middleware<SlackEventMiddlewareArgs>;

123

124

/**

125

* Middleware that matches actions against constraint criteria

126

* @param constraints - Action constraints to match against

127

* @returns Middleware that only processes matching actions

128

*/

129

function matchConstraints<T>(

130

constraints: ActionConstraints

131

): Middleware<SlackActionMiddlewareArgs>;

132

133

/**

134

* Middleware that filters messages by subtype

135

* @param subtypeValue - Message subtype to match

136

* @returns Middleware that only processes messages with matching subtype

137

*/

138

function subtype(

139

subtypeValue: string

140

): Middleware<SlackEventMiddlewareArgs<'message'>>;

141

```

142

143

**Usage Examples:**

144

145

```typescript

146

import { App, matchMessage, matchCommandName } from "@slack/bolt";

147

148

const app = new App({

149

token: process.env.SLACK_BOT_TOKEN,

150

signingSecret: process.env.SLACK_SIGNING_SECRET

151

});

152

153

// Match messages containing "hello"

154

app.use(matchMessage("hello"), async ({ message, say }) => {

155

await say(`Hello <@${message.user}>!`);

156

});

157

158

// Match messages with regex pattern

159

app.use(matchMessage(/ticket-(\d+)/), async ({ message, say, context }) => {

160

const ticketId = context.matches?.[1];

161

await say(`Looking up ticket ${ticketId}`);

162

});

163

164

// Match specific command names

165

app.use(matchCommandName("/deploy"), async ({ command, ack, respond }) => {

166

await ack();

167

await respond("Starting deployment...");

168

});

169

170

// Match multiple command patterns

171

app.use(matchCommandName(/^\/(help|info)$/), async ({ command, ack, respond }) => {

172

await ack();

173

await respond("Here's some helpful information...");

174

});

175

```

176

177

### Utility Middleware

178

179

General-purpose middleware for common functionality.

180

181

```typescript { .api }

182

/**

183

* Middleware that ignores events from the bot itself

184

* Prevents infinite loops when the bot responds to its own messages

185

*/

186

const ignoreSelf: Middleware<AnyMiddlewareArgs>;

187

188

/**

189

* Middleware that auto acknowledges the request received

190

* Automatically calls ack() if available, then continues to next middleware

191

*/

192

const autoAcknowledge: Middleware<AnyMiddlewareArgs>;

193

194

/**

195

* Middleware that filters out messages that don't start with a direct mention

196

* Only allows messages that begin with @bot_user_id

197

* @returns Middleware that only processes direct mentions

198

*/

199

const directMention: Middleware<SlackEventMiddlewareArgs<'message'>>;

200

201

/**

202

* Middleware that filters messages by subtype

203

* @param subtype - Message subtype to match (e.g., "bot_message", "file_share")

204

* @returns Middleware that only processes messages with matching subtype

205

*/

206

function subtype(subtype: string): Middleware<SlackEventMiddlewareArgs<'message'>>;

207

208

/**

209

* Type guard to check if options object contains event middleware options

210

* @param optionOrListener - Options object or listener function

211

* @returns True if input is SlackEventMiddlewareArgsOptions

212

*/

213

function isSlackEventMiddlewareArgsOptions<EventType extends string = string>(

214

optionOrListener: SlackEventMiddlewareArgsOptions | Middleware<SlackEventMiddlewareArgs<EventType>>

215

): optionOrListener is SlackEventMiddlewareArgsOptions;

216

```

217

218

**Usage Examples:**

219

220

```typescript

221

import {

222

App,

223

ignoreSelf,

224

autoAcknowledge,

225

directMention,

226

subtype

227

} from "@slack/bolt";

228

229

const app = new App({

230

token: process.env.SLACK_BOT_TOKEN,

231

signingSecret: process.env.SLACK_SIGNING_SECRET

232

});

233

234

// Add ignoreSelf middleware globally

235

app.use(ignoreSelf);

236

237

// Now the bot won't respond to its own messages

238

app.message("hello", async ({ message, say }) => {

239

await say("Hello there!"); // Won't trigger itself

240

});

241

242

// Auto-acknowledge all interactions

243

app.use(autoAcknowledge);

244

245

// Handle direct mentions only

246

app.message(directMention, async ({ message, say }) => {

247

await say(`You mentioned me, <@${message.user}>!`);

248

});

249

250

// Handle only bot messages

251

app.message(subtype("bot_message"), async ({ message, say }) => {

252

// This will only process messages from other bots

253

console.log("Received bot message:", message.text);

254

});

255

256

// Handle file share messages

257

app.message(subtype("file_share"), async ({ message, client }) => {

258

// Process file sharing events

259

console.log("File shared:", message.files);

260

});

261

262

// Custom ignore middleware example

263

app.use(async ({ context, body, next }) => {

264

// Skip if this is a bot message (alternative to ignoreSelf)

265

if (body.event?.bot_id) {

266

return;

267

}

268

await next();

269

});

270

```

271

272

### Custom Middleware Creation

273

274

Create custom middleware functions for specific application needs.

275

276

```typescript { .api }

277

/**

278

* Custom middleware function type

279

* @param args - Middleware arguments including context, logger, client, and next

280

*/

281

type Middleware<Args, CustomContext = StringIndexed> = (

282

args: Args & AllMiddlewareArgs<CustomContext>

283

) => Promise<void>;

284

285

interface AllMiddlewareArgs<CustomContext = StringIndexed> {

286

/** Request context with bot tokens and user information */

287

context: Context & CustomContext;

288

/** Logger instance for debugging and monitoring */

289

logger: Logger;

290

/** Slack Web API client for making API calls */

291

client: WebClient;

292

/** Function to call next middleware in the chain */

293

next: NextFn;

294

}

295

```

296

297

**Usage Examples:**

298

299

```typescript

300

import { App, Middleware, AnyMiddlewareArgs } from "@slack/bolt";

301

302

const app = new App({

303

token: process.env.SLACK_BOT_TOKEN,

304

signingSecret: process.env.SLACK_SIGNING_SECRET

305

});

306

307

// Custom logging middleware

308

const loggingMiddleware: Middleware<AnyMiddlewareArgs> = async ({

309

logger,

310

body,

311

next

312

}) => {

313

const startTime = Date.now();

314

315

logger.info(`Processing ${body.type || 'unknown'} event`);

316

317

await next();

318

319

const duration = Date.now() - startTime;

320

logger.info(`Completed processing in ${duration}ms`);

321

};

322

323

// Custom authorization middleware

324

const authMiddleware: Middleware<AnyMiddlewareArgs> = async ({

325

context,

326

client,

327

next

328

}) => {

329

// Add custom user data to context

330

if (context.userId) {

331

context.userData = await getUserData(context.userId);

332

}

333

334

await next();

335

};

336

337

// Rate limiting middleware

338

const rateLimitMiddleware: Middleware<AnyMiddlewareArgs> = async ({

339

context,

340

logger,

341

next

342

}) => {

343

const userId = context.userId;

344

if (!userId) {

345

await next();

346

return;

347

}

348

349

const isAllowed = await checkRateLimit(userId);

350

if (!isAllowed) {

351

logger.warn(`Rate limit exceeded for user ${userId}`);

352

return; // Don't call next(), stopping the middleware chain

353

}

354

355

await next();

356

};

357

358

// Apply custom middleware

359

app.use(loggingMiddleware);

360

app.use(authMiddleware);

361

app.use(rateLimitMiddleware);

362

363

// Conditional middleware

364

const adminOnlyMiddleware: Middleware<AnyMiddlewareArgs> = async ({

365

context,

366

client,

367

next

368

}) => {

369

const isAdmin = await checkIfAdmin(context.userId);

370

if (!isAdmin) {

371

return; // Stop processing if not admin

372

}

373

374

await next();

375

};

376

377

// Use conditional middleware for specific commands

378

app.command("/admin", adminOnlyMiddleware, async ({ command, ack, respond }) => {

379

await ack();

380

await respond("Admin command executed!");

381

});

382

```

383

384

## Middleware Processing

385

386

Understanding how middleware chains work in Slack Bolt.

387

388

```typescript { .api }

389

/**

390

* Next function type for calling the next middleware in the chain

391

*/

392

type NextFn = () => Promise<void>;

393

394

/**

395

* Middleware execution follows this pattern:

396

* 1. Global middleware (added with app.use())

397

* 2. Built-in filtering middleware (if applicable)

398

* 3. Listener-specific middleware

399

* 4. Final listener function

400

*/

401

```

402

403

**Middleware Chain Example:**

404

405

```typescript

406

const app = new App({

407

token: process.env.SLACK_BOT_TOKEN,

408

signingSecret: process.env.SLACK_SIGNING_SECRET

409

});

410

411

// 1. Global middleware - runs for all requests

412

app.use(async ({ logger, next }) => {

413

logger.info("Global middleware start");

414

await next();

415

logger.info("Global middleware end");

416

});

417

418

// 2. Event listener with middleware chain

419

app.message(

420

// Built-in pattern matching middleware

421

"hello",

422

// Custom middleware for this listener

423

async ({ logger, next }) => {

424

logger.info("Message middleware start");

425

await next();

426

logger.info("Message middleware end");

427

},

428

// Final listener function

429

async ({ message, say, logger }) => {

430

logger.info("Processing message");

431

await say(`Hello <@${message.user}>!`);

432

}

433

);

434

435

// Execution order for "hello" message:

436

// 1. Global middleware start

437

// 2. Built-in message matching

438

// 3. Message middleware start

439

// 4. Processing message

440

// 5. Message middleware end

441

// 6. Global middleware end

442

```

443

444

## Constraint Types

445

446

Type definitions for matching constraints used in middleware.

447

448

```typescript { .api }

449

interface ActionConstraints {

450

type?: string;

451

action_id?: string | RegExp;

452

block_id?: string | RegExp;

453

callback_id?: string | RegExp;

454

}

455

456

interface OptionsConstraints {

457

action_id?: string | RegExp;

458

block_id?: string | RegExp;

459

callback_id?: string | RegExp;

460

}

461

462

interface ShortcutConstraints {

463

type?: 'shortcut' | 'message_action';

464

callback_id?: string | RegExp;

465

}

466

467

interface ViewConstraints {

468

callback_id?: string | RegExp;

469

type?: 'view_submission' | 'view_closed';

470

}

471

472

type EventTypePattern = string | RegExp;

473

```