response-kit
v2.0.0
Published
Production-grade API response utility for Node.js and Express.js with middleware support, global configuration, and async handlers
Maintainers
Readme
Response Kit v2.0 🚀
A production-grade, lightweight API response utility for Express.js and Node.js applications.
Version 2 brings middleware support, global configuration, async handlers, and a scalable architecture while maintaining 100% backward compatibility with v1.
✨ Why Response Kit?
✅ Standardized API responses across your entire application
✅ Express middleware for cleaner route handlers
✅ Global configuration - customize once, apply everywhere
✅ Async handler - eliminate repetitive try-catch blocks
✅ TypeScript support with comprehensive type definitions
✅ Zero dependencies - lightweight and fast
✅ Production-ready - follows SOLID principles and clean architecture
✅ Backward compatible - upgrade from v1 without breaking changes
📦 Installation
npm install response-kit🎯 Quick Start
Method 1: Using Middleware (Recommended - v2)
const express = require('express');
const response = require('response-kit');
const app = express();
// Attach response helpers to res object
app.use(response.middleware());
app.get('/user/:id', async (req, res) => {
const user = await getUserById(req.params.id);
if (!user) {
return res.notFound('User not found');
}
return res.success(user, 'User fetched successfully');
});
app.listen(3000);Method 2: Direct Function Calls (v1 - Still Supported)
const response = require('response-kit');
app.get('/user/:id', async (req, res) => {
const user = await getUserById(req.params.id);
if (!user) {
return response.notFound(res, 'User not found');
}
return response.success(res, user, 'User fetched successfully');
});🔧 Configuration
Global Configuration
Configure once, apply everywhere:
const response = require('response-kit');
response.configure({
successKey: 'success', // Key for success status
dataKey: 'data', // Key for response data
messageKey: 'message', // Key for messages
errorKey: 'errors', // Key for error details
includeTimestamp: true, // Add timestamp to responses
includeRequestId: true, // Add request ID to responses
includeMeta: false, // Add request metadata
});Example Response with Configuration:
{
"success": true,
"message": "User created successfully",
"data": {
"id": 1,
"name": "John Doe"
},
"timestamp": "2024-01-15T10:30:00.000Z",
"requestId": "1705315800000-a1b2c3d4e"
}Custom Keys Example
response.configure({
successKey: 'status',
dataKey: 'result',
messageKey: 'msg',
errorKey: 'validationErrors',
});Output:
{
"status": true,
"msg": "Success",
"result": { "id": 1 }
}🎭 Middleware Usage
Basic Setup
const express = require('express');
const response = require('response-kit');
const app = express();
// Apply middleware globally
app.use(response.middleware());
// Now all routes have access to response helpers via res object
app.get('/users', (req, res) => {
res.success(users, 'Users fetched successfully');
});Available Methods on res Object
After applying middleware, the following methods are available:
res.success(data, message, statusCode)res.created(data, message)res.badRequest(message)res.unauthorized(message)res.forbidden(message)res.notFound(message)res.conflict(message)res.internalError(message)res.validationError(errors, message)res.paginate(data, page, limit, total)
🔄 Async Handler
Eliminate repetitive try-catch blocks in your route handlers.
Without Async Handler ❌
app.get('/users/:id', async (req, res) => {
try {
const user = await User.findById(req.params.id);
return res.success(user);
} catch (error) {
return res.internalError(error.message);
}
});With Async Handler ✅
app.get('/users/:id', response.asyncHandler(async (req, res) => {
const user = await User.findById(req.params.id);
return res.success(user);
}));Any errors thrown inside the handler are automatically caught and passed to Express error handling middleware.
Complete Example with Error Handler
const express = require('express');
const response = require('response-kit');
const app = express();
app.use(response.middleware());
// Routes with async handler
app.get('/users/:id', response.asyncHandler(async (req, res) => {
const user = await User.findById(req.params.id);
if (!user) {
return res.notFound('User not found');
}
return res.success(user);
}));
// Global error handler
app.use((err, req, res, next) => {
console.error(err.stack);
res.internalError(err.message || 'Something went wrong');
});
app.listen(3000);📖 API Reference
Success Responses
success(data, message, statusCode)
Send a successful response.
res.success(
{ id: 1, name: 'John' },
'User fetched successfully',
200
);Response:
{
"success": true,
"message": "User fetched successfully",
"data": { "id": 1, "name": "John" }
}created(data, message)
Send a 201 Created response.
res.created(
{ id: 1, name: 'John' },
'User created successfully'
);Status Code: 201
Error Responses
badRequest(message)
Send a 400 Bad Request response.
res.badRequest('Invalid input data');Status Code: 400
unauthorized(message)
Send a 401 Unauthorized response.
res.unauthorized('Invalid credentials');Status Code: 401
forbidden(message)
Send a 403 Forbidden response.
res.forbidden('Access denied');Status Code: 403
notFound(message)
Send a 404 Not Found response.
res.notFound('User not found');Status Code: 404
conflict(message)
Send a 409 Conflict response.
res.conflict('Email already exists');Status Code: 409
internalError(message)
Send a 500 Internal Server Error response.
res.internalError('Database connection failed');Status Code: 500
Validation Errors
validationError(errors, message)
Send a 422 Unprocessable Entity response with validation errors.
res.validationError({
email: 'Email is required',
password: 'Password must be at least 8 characters'
}, 'Validation failed');Response:
{
"success": false,
"message": "Validation failed",
"errors": {
"email": "Email is required",
"password": "Password must be at least 8 characters"
}
}Status Code: 422
Pagination
paginate(data, page, limit, total)
Send a paginated response.
res.paginate(users, 1, 10, 100);Response:
{
"success": true,
"data": [...],
"pagination": {
"page": 1,
"limit": 10,
"total": 100,
"totalPages": 10
}
}🔄 Migration Guide (v1 to v2)
Good News: Zero Breaking Changes! 🎉
All v1 APIs work exactly as before. You can upgrade and adopt v2 features gradually.
Step 1: Update Package
npm install response-kit@latestStep 2: Keep Using v1 API (Optional)
// This still works perfectly
response.success(res, data, message);
response.notFound(res, 'Not found');Step 3: Gradually Adopt v2 Features
Add Middleware
app.use(response.middleware());
// Now you can use
res.success(data, message);
res.notFound('Not found');Add Configuration
response.configure({
includeTimestamp: true,
includeRequestId: true,
});Use Async Handler
app.get('/users', response.asyncHandler(async (req, res) => {
const users = await User.find();
res.success(users);
}));Migration Examples
Before (v1):
app.get('/users/:id', async (req, res) => {
try {
const user = await User.findById(req.params.id);
if (!user) {
return response.notFound(res, 'User not found');
}
return response.success(res, user);
} catch (error) {
return response.internalError(res, error.message);
}
});After (v2):
app.use(response.middleware());
app.get('/users/:id', response.asyncHandler(async (req, res) => {
const user = await User.findById(req.params.id);
if (!user) {
return res.notFound('User not found');
}
return res.success(user);
}));💡 Complete Examples
Example 1: RESTful User API
const express = require('express');
const response = require('response-kit');
const app = express();
app.use(express.json());
app.use(response.middleware());
// Configure globally
response.configure({
includeTimestamp: true,
includeRequestId: true,
});
// Get all users with pagination
app.get('/users', response.asyncHandler(async (req, res) => {
const page = parseInt(req.query.page) || 1;
const limit = parseInt(req.query.limit) || 10;
const users = await User.find()
.skip((page - 1) * limit)
.limit(limit);
const total = await User.countDocuments();
return res.paginate(users, page, limit, total);
}));
// Get user by ID
app.get('/users/:id', response.asyncHandler(async (req, res) => {
const user = await User.findById(req.params.id);
if (!user) {
return res.notFound('User not found');
}
return res.success(user, 'User fetched successfully');
}));
// Create new user
app.post('/users', response.asyncHandler(async (req, res) => {
const { email, name, password } = req.body;
// Validation
if (!email || !name || !password) {
return res.validationError({
email: !email ? 'Email is required' : undefined,
name: !name ? 'Name is required' : undefined,
password: !password ? 'Password is required' : undefined,
});
}
// Check if user exists
const existingUser = await User.findOne({ email });
if (existingUser) {
return res.conflict('User with this email already exists');
}
// Create user
const user = await User.create({ email, name, password });
return res.created(user, 'User created successfully');
}));
// Update user
app.put('/users/:id', response.asyncHandler(async (req, res) => {
const user = await User.findByIdAndUpdate(
req.params.id,
req.body,
{ new: true }
);
if (!user) {
return res.notFound('User not found');
}
return res.success(user, 'User updated successfully');
}));
// Delete user
app.delete('/users/:id', response.asyncHandler(async (req, res) => {
const user = await User.findByIdAndDelete(req.params.id);
if (!user) {
return res.notFound('User not found');
}
return res.success(null, 'User deleted successfully');
}));
// Global error handler
app.use((err, req, res, next) => {
console.error(err.stack);
res.internalError(err.message || 'Internal server error');
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});Example 2: Authentication API
const express = require('express');
const response = require('response-kit');
const jwt = require('jsonwebtoken');
const app = express();
app.use(express.json());
app.use(response.middleware());
// Login
app.post('/auth/login', response.asyncHandler(async (req, res) => {
const { email, password } = req.body;
if (!email || !password) {
return res.badRequest('Email and password are required');
}
const user = await User.findOne({ email });
if (!user || !await user.comparePassword(password)) {
return res.unauthorized('Invalid credentials');
}
const token = jwt.sign({ id: user._id }, process.env.JWT_SECRET);
return res.success({ token, user }, 'Login successful');
}));
// Protected route
app.get('/profile', authenticateToken, response.asyncHandler(async (req, res) => {
const user = await User.findById(req.user.id);
if (!user) {
return res.notFound('User not found');
}
return res.success(user);
}));
// Middleware
function authenticateToken(req, res, next) {
const token = req.headers['authorization']?.split(' ')[1];
if (!token) {
return res.unauthorized('Access token required');
}
try {
req.user = jwt.verify(token, process.env.JWT_SECRET);
next();
} catch (error) {
return res.forbidden('Invalid or expired token');
}
}
app.listen(3000);📚 Documentation
🤝 Contributing
Contributions are welcome! Please read CONTRIBUTING.md for details.
📝 Changelog
See CHANGELOG.md for release notes.
📄 License
MIT © Piyush Yadav
🌟 Features Summary
| Feature | v1 | v2 | |---------|----|----| | Success/Error responses | ✅ | ✅ | | Pagination | ✅ | ✅ | | TypeScript support | ✅ | ✅ | | Express middleware | ❌ | ✅ | | Global configuration | ❌ | ✅ | | Async handler | ❌ | ✅ | | Request ID tracking | ❌ | ✅ | | Timestamp support | ❌ | ✅ | | Custom response keys | ❌ | ✅ | | Backward compatible | - | ✅ |
🚀 Why Upgrade to v2?
- Cleaner Code: Middleware reduces boilerplate
- Flexible Configuration: Customize response structure globally
- Better Error Handling: Async handler eliminates try-catch blocks
- Production Features: Request IDs, timestamps, metadata
- Modern Architecture: SOLID principles, scalable structure
- Zero Risk: 100% backward compatible with v1
⭐ Show Your Support
If you find this package helpful, please give it a star on GitHub!
Built with ❤️ by developers, for developers.
