grom-utils
Version:
A lightweight utility package for simplified error handling, validation, and API responses.
115 lines (103 loc) • 3.89 kB
JavaScript
// index.js
import ApiResponse from "./Utility/Apiresponse.js";
import ApiError from "./Utility/ApiError.js";
class Grom {
constructor() {
// Map to store rate limit logs per IP
this.rateLimits = new Map();
}
/**
* Wraps an async function to catch errors and delegate to Express error middleware.
* @param {Function} fn - The async route handler.
* @returns {Function}
*/
grAsyncHandler(fn) {
return async (req, res, next) => {
try {
await fn(req, res, next);
} catch (error) {
next(error);
}
};
}
/**
* Checks a condition; if false, throws an ApiError.
* @param {boolean} condition - The condition to check.
* @param {number} [statusCode=400] - HTTP status code.
* @param {string} [message="Bad Request"] - Error message.
*/
grCheck(condition, statusCode = 400, message = "Bad Request") {
if (!condition) {
throw new ApiError(statusCode, message);
}
}
/**
* Generates a standard API response.
* @param {number} [statusCode=200] - HTTP status code.
* @param {any} [data=null] - Data to return.
* @param {string} [message="Success"] - Response message.
* @param {object} [meta={}] - Additional meta information (e.g., pagination).
* @returns {ApiResponse}
*/
grResponse(statusCode = 200, data = null, message = "Success", meta = {}) {
return new ApiResponse(statusCode, data, message, meta);
}
/**
* Validates input data against a simple schema.
* @param {object} schema - Expected keys and their types (e.g., { name: "string", age: "number" }).
* @param {object} data - Actual data to validate.
* @throws {ApiError} - If validation fails.
*/
grValidate(schema, data) {
const errors = [];
for (const key in schema) {
const expectedType = schema[key];
if (typeof data[key] !== expectedType) {
errors.push(`'${key}' should be of type '${expectedType}', got '${typeof data[key]}'`);
}
}
if (errors.length) {
throw new ApiError(400, "Validation Error", errors);
}
}
/**
* Express middleware for rate limiting based on IP address.
* @param {number} maxRequests - Maximum allowed requests.
* @param {number} timeWindow - Time window in milliseconds.
* @returns {Function} Express middleware.
*/
grRateLimit(maxRequests, timeWindow) {
return (req, res, next) => {
const ip = req.ip;
const now = Date.now();
const requestLogs = this.rateLimits.get(ip) || [];
const filteredLogs = requestLogs.filter(timestamp => now - timestamp < timeWindow);
filteredLogs.push(now);
this.rateLimits.set(ip, filteredLogs);
if (filteredLogs.length > maxRequests) {
return next(new ApiError(429, "Too many requests, slow down!"));
}
next();
};
}
/**
* Logs messages with a timestamp and color-coded levels.
* @param {string} level - Log level ("info", "warn", or "error").
* @param {string} message - The message to log.
*/
grLogger(level, message) {
const colors = { info: "\x1b[36m", warn: "\x1b[33m", error: "\x1b[31m" };
const timestamp = new Date().toISOString();
console.log(`${colors[level] || ""}[${level.toUpperCase()}] ${timestamp}: ${message}\x1b[0m`);
}
}
const grom = new Grom();
// Export named functions by binding them to the grom instance
export const grAsyncHandler = grom.grAsyncHandler.bind(grom);
export const grCheck = grom.grCheck.bind(grom);
export const grResponse = grom.grResponse.bind(grom);
export const grValidate = grom.grValidate.bind(grom);
export const grRateLimit = grom.grRateLimit.bind(grom);
export const grLogger = grom.grLogger.bind(grom);
// Optionally, you can also export the class itself if needed
export default Grom;