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
- No need for try-catch blocks
- Clean, readable code
- Consistent error handling
- Automatic error propagation
- 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
- Always use
asyncHandler
for async route handlers - Throw appropriate errors with status codes
- Keep route handlers focused and concise
- Use TypeScript for better type safety
- 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' });
}));