Skip to main content

Async Handler

ExpressPro provides an asyncHandler utility to simplify error handling in asynchronous route handlers.

Overview

The asyncHandler is a middleware that wraps asynchronous route handlers and automatically catches any errors, passing them to Express's error handling middleware.

Usage

import express from 'expresspro';

const app = express();

app.get('/users', express.asyncHandler(async (req, res) => {
const users = await User.findAll();
res.json({ users });
}));

Benefits

  1. No need for try-catch blocks
  2. Clean, readable code
  3. Consistent error handling
  4. Automatic error propagation
  5. TypeScript support

Examples

Basic Usage

app.get('/users/:id', express.asyncHandler(async (req, res) => {
const user = await User.findById(req.params.id);

if (!user) {
throw new express.AppError('User not found', 404);
}

res.json({ user });
}));

Database Operations

app.post('/users', express.asyncHandler(async (req, res) => {
const user = await User.create(req.body);
res.status(201).json({ user });
}));

Multiple Async Operations

app.get('/user/:id/posts', express.asyncHandler(async (req, res) => {
const user = await User.findById(req.params.id);
const posts = await Post.findByUserId(user.id);
const comments = await Comment.findByPostIds(posts.map(p => p.id));

res.json({ user, posts, comments });
}));

Error Handling

The asyncHandler automatically catches errors and passes them to the next middleware:

app.get('/users/:id', express.asyncHandler(async (req, res) => {
const user = await User.findById(req.params.id);

if (!user) {
throw new express.AppError('User not found', 404);
}

res.json({ user });
}));

app.use(express.error); // Global error handler

TypeScript Support

The asyncHandler is fully typed and works with TypeScript:

import { Request, Response } from 'express';

app.get('/users', express.asyncHandler(async (req: Request, res: Response) => {
const users = await User.findAll();
res.json({ users });
}));

Best Practices

  1. Always use asyncHandler for async route handlers
  2. Throw appropriate errors with status codes
  3. Keep route handlers focused and concise
  4. Use TypeScript for better type safety
  5. Handle specific error cases explicitly

Common Patterns

Validation

app.post('/users', express.asyncHandler(async (req, res) => {
const { error, value } = validateUser(req.body);

if (error) {
throw new express.AppError('Validation failed', 400);
}

const user = await User.create(value);
res.status(201).json({ user });
}));

File Operations

app.post('/upload', express.asyncHandler(async (req, res) => {
const file = req.file;

if (!file) {
throw new express.AppError('No file uploaded', 400);
}

await processFile(file);
res.json({ message: 'File processed successfully' });
}));

Database Transactions

app.post('/transfer', express.asyncHandler(async (req, res) => {
const { from, to, amount } = req.body;

await db.transaction(async (t) => {
await Account.decrement({ balance: amount }, { where: { id: from }, transaction: t });
await Account.increment({ balance: amount }, { where: { id: to }, transaction: t });
});

res.json({ message: 'Transfer successful' });
}));