devdad-express-utils
v1.6.0
Published
Reusable Express.js utilities for error handling, async wrapping, and more
Downloads
1,070
Maintainers
Readme
Express Utils
A collection of reusable utilities for Express.js applications, including error handling, async route wrapping, custom error classes, MongoDB connection management, and Winston-based logging.
Installation
npm install devdad-express-utils
# or
yarn add devdad-express-utils
# or
pnpm add devdad-express-utilsUsage
Error Handling
import express from "express";
import { errorHandler, AppError } from "devdad-express-utils";
const app = express();
// Your routes here
// Use the error handler as the last middleware
app.use(errorHandler);
// In your controllers, throw AppError for operational errors
throw new AppError("Something went wrong", 400);Async Route Wrapping
import { catchAsync } from "devdad-express-utils";
const getUsers = catchAsync(async (req, res, next) => {
const users = await User.find();
res.json(users);
});
app.get("/users", getUsers);Custom Error Class
import { AppError } from "devdad-express-utils";
throw new AppError("Validation failed", 400, ["Email is required"]);Response Formatting
Standardize API responses with consistent JSON structure.
import { sendSuccess, sendError, sendPaginated } from "devdad-express-utils";
// Success response
sendSuccess(res, { id: 1, name: "John" }, "User fetched", 200);
// Chain additional response methods
sendSuccess(res, { id: 1, name: "John" })
.cookie("session", "abc123")
.setHeader("X-Custom", "value");
// Error response
sendError(res, "User not found", 404);Database Connection
MongoDB connection utility with automatic reconnection, exponential backoff, and configurable retry logic.
import { connectDB, getDBStatus, resetDBConnection } from "devdad-express-utils";
// Connect to MongoDB (ensure MONGO_URI is set in environment)
await connectDB();
// Check connection status
const status = getDBStatus();
console.log(status); // { isConnected: true, readyState: 1, host: '...', name: '...', retryCount: 0 }
// Manually reset and retry (useful after Docker container restarts)
await resetDBConnection();Environment Variables
- MONGO_URI: MongoDB connection string (required)
- DB_MAX_RETRIES: Maximum connection retry attempts (default: 10)
- DB_RETRY_INTERVAL: Initial retry interval in milliseconds (default: 3000)
- NODE_ENV: Set to 'production' to exit after max retries, 'development' to keep process alive
Retry Behavior
- Exponential backoff: Retry intervals increase exponentially (3s → 6s → 12s → 24s → 30s max)
- Random jitter: Adds up to 1 second of random delay to prevent thundering herd
- Docker-friendly: Higher default retry count (10) accommodates container startup times
- Development mode: Process stays alive after max retries for manual recovery
- Production mode: Process exits after max retries to allow container restart
Logging
Winston-based logger with configurable service name and environment-aware transports.
import { logger } from "devdad-express-utils";
// Log messages at different levels
logger.info("User logged in", { userId: 123 });
logger.error("Database connection failed", { error: err.message });
logger.debug("Processing request", { requestId: "abc-123" });Configuration
- Service Name: Set
SERVICE_NAMEenvironment variable to customize the service name in logs (defaults to "express-utils") - Log Level: "debug" in development, "info" in production
- Transports:
- Development: Console (colored) + error.log + combined.log files
- Production: Console only (suitable for platforms like Railway)
Log Files
In development, logs are written to:
error.log: Error level and abovecombined.log: All log levels
Error Handling Patterns
Using AppError
For operational errors (expected errors like validation):
// In controllers wrapped with catchAsync
const createUser = catchAsync(async (req, res, next) => {
// Validation fails
return next(new AppError("Email is required", 400));
});
// Or for unexpected errors
throw new AppError("Database connection failed", 500);Why next(new AppError()) over throw?
next()passes the error to your error handler middleware- Allows centralized error handling and formatting
- Better for Express middleware pattern
throwis more for unexpected errors that bubble up
Complete Example
const express = require("express");
const { AppError, catchAsync, errorHandler } = require("devdad-express-utils");
const app = express();
const getUser = catchAsync(async (req, res, next) => {
const user = await User.findById(req.params.id);
if (!user) {
return next(new AppError("User not found", 404));
}
res.json(user);
});
app.get("/users/:id", getUser);
// Error handler should be last
app.use(errorHandler);JavaScript Usage
const { AppError, catchAsync, errorHandler } = require("devdad-express-utils");
// Or with ES modules
import { AppError, catchAsync, errorHandler } from "devdad-express-utils";API
AppError
Custom error class for operational errors.
new AppError(message: string, statusCode: number, errors?: string[])catchAsync
Higher-order function to wrap async route handlers and catch errors.
catchAsync(fn: (req, res, next) => Promise<any>) => (req, res, next) => voiderrorHandler
Express error handling middleware with detailed logging in development.
errorHandler(err: any, req: Request, res: Response, next: NextFunction) => voidsendSuccess
Sends a standardized success response. Returns the Response object for method chaining.
sendSuccess(res: Response, data: any, message?: string, statusCode?: number) => ResponsesendError
Sends a standardized error response.
sendError(res: Response, message: string, statusCode?: number, data?: any) => voidconnectDB
Connects to MongoDB with retry logic and automatic reconnection.
connectDB() => Promise<void>getDBStatus
Gets the current MongoDB connection status.
getDBStatus() => { isConnected: boolean; readyState: number; host: string; name: string; retryCount: number; }resetDBConnection
Manually resets retry count and attempts reconnection. Useful for recovering from Docker container restarts.
resetDBConnection() => Promise<void>logger
Winston logger instance with JSON formatting, timestamps, and error stack traces.
logger: winston.Logger;Development
# Install dependencies
pnpm install
# Build the package
pnpm run build
# Publish to npm
npm publishLicense
ISC
