Package Exports
- @ooneex/exception
- @ooneex/exception/package.json
Readme
@ooneex/exception
A comprehensive TypeScript/JavaScript library for creating structured, HTTP status-aware exceptions. This package provides a robust foundation for error handling in web applications with built-in support for HTTP status codes, structured data, and stack trace parsing.
Features
✅ HTTP Status Integration - Built-in support for HTTP status codes via @ooneex/http-status
✅ Type-Safe - Full TypeScript support with generic data types
✅ Structured Data - Attach custom data objects to exceptions
✅ Stack Trace Parsing - Parse stack traces into structured JSON format
✅ Predefined Exceptions - Common HTTP exceptions (400, 401, 404, 405)
✅ Cross-Platform - Works in Browser, Node.js, Bun, and Deno
✅ Immutable Data - Exception data is automatically frozen
✅ Error Wrapping - Wrap native Error objects with additional context
Installation
Bun
bun add @ooneex/exceptionpnpm
pnpm add @ooneex/exceptionYarn
yarn add @ooneex/exceptionnpm
npm install @ooneex/exceptionUsage
Basic Usage
import { Exception } from '@ooneex/exception';
// Simple exception with message
const exception = new Exception('Something went wrong');
console.log(exception.message); // "Something went wrong"
console.log(exception.name); // "Exception"
console.log(exception.date); // Date object
// Exception with HTTP status and data
const detailedException = new Exception('User not found', {
status: 404,
data: {
userId: 123,
searchCriteria: { email: 'user@example.com' }
}
});
console.log(detailedException.status); // 404
console.log(detailedException.data); // { userId: 123, searchCriteria: {...} }Using Predefined Exceptions
import {
BadRequestException,
UnauthorizedException,
NotFoundException,
MethodNotAllowedException
} from '@ooneex/exception';
// 400 Bad Request
throw new BadRequestException('Invalid input data', {
field: 'email',
value: 'invalid-email',
rule: 'Must be a valid email address'
});
// 401 Unauthorized
throw new UnauthorizedException('Token expired', {
token: 'eyJ...',
expiredAt: new Date()
});
// 404 Not Found
throw new NotFoundException('Resource not found', {
resourceType: 'User',
id: 123
});
// 405 Method Not Allowed
throw new MethodNotAllowedException('POST not allowed on this endpoint', {
method: 'POST',
allowedMethods: ['GET', 'PUT']
});Error Wrapping
import { Exception } from '@ooneex/exception';
try {
// Some operation that might fail
JSON.parse('invalid json');
} catch (error) {
// Wrap the native error with additional context
throw new Exception(error as Error, {
status: 400,
data: {
operation: 'JSON parsing',
input: 'invalid json'
}
});
}Stack Trace Parsing
import { Exception } from '@ooneex/exception';
const exception = new Exception('Parsing failed');
const stackFrames = exception.stackToJson();
console.log(stackFrames);
// [
// {
// functionName: 'parseData',
// fileName: '/path/to/file.ts',
// lineNumber: 42,
// columnNumber: 15,
// source: ' at parseData (/path/to/file.ts:42:15)'
// },
// ...
// ]Generic Data Types
import { Exception } from '@ooneex/exception';
// Define custom data interface
interface ValidationError {
field: string;
value: unknown;
rule: string;
message: string;
}
// Create typed exception
const validationException = new Exception<ValidationError>('Validation failed', {
status: 400,
data: {
field: 'email',
value: 'not-an-email',
rule: 'email',
message: 'Must be a valid email address'
}
});
// TypeScript ensures type safety
console.log(validationException.data?.field); // string
console.log(validationException.data?.rule); // stringAPI Reference
Exception<T> Class
The main exception class providing structured error handling with optional HTTP status and custom data.
Constructor
new Exception<T>(message: string | Error, options?: {
status?: StatusCodeType;
data?: T;
})Parameters:
message- Error message string or native Error object to wrapoptions.status- HTTP status code (from @ooneex/http-status)options.data- Custom data object (automatically frozen)
Properties
date: Date (readonly)
Timestamp when the exception was created.
const exception = new Exception('Error occurred');
console.log(exception.date); // 2024-01-15T10:30:00.000Zstatus?: StatusCodeType (readonly)
HTTP status code associated with the exception.
const exception = new Exception('Not found', { status: 404 });
console.log(exception.status); // 404data?: T (readonly)
Custom data object associated with the exception. Automatically frozen to prevent mutations.
const exception = new Exception('Error', {
data: { userId: 123, action: 'delete' }
});
console.log(exception.data); // { userId: 123, action: 'delete' }
// exception.data.userId = 456; // TypeError: Cannot assign to read only propertynative?: Error (readonly)
Original native Error object when wrapping existing errors.
const originalError = new Error('Original message');
const exception = new Exception(originalError);
console.log(exception.native); // Original Error objectmessage: string
Error message (inherited from Error).
name: string
Exception name (inherited from Error).
stack?: string
Stack trace string (inherited from Error).
Methods
stackToJson(): ExceptionStackFrameType[] | null
Parses the stack trace into a structured JSON format.
Returns: Array of stack frame objects or null if no stack trace available.
Example:
const exception = new Exception('Error occurred');
const frames = exception.stackToJson();
if (frames) {
frames.forEach(frame => {
console.log(`Function: ${frame.functionName}`);
console.log(`File: ${frame.fileName}:${frame.lineNumber}:${frame.columnNumber}`);
console.log(`Source: ${frame.source}`);
});
}Predefined Exception Classes
BadRequestException<T>
HTTP 400 Bad Request exception.
new BadRequestException<T>(message: string, data?: T)Example:
throw new BadRequestException('Invalid request data', {
validationErrors: ['email is required', 'age must be a number']
});UnauthorizedException<T>
HTTP 401 Unauthorized exception.
new UnauthorizedException<T>(message: string, data?: T)Example:
throw new UnauthorizedException('Access token expired', {
tokenType: 'Bearer',
expiredAt: new Date()
});NotFoundException<T>
HTTP 404 Not Found exception.
new NotFoundException<T>(message: string, data?: T)Example:
throw new NotFoundException('User not found', {
userId: 123,
searchedBy: 'email'
});MethodNotAllowedException<T>
HTTP 405 Method Not Allowed exception.
new MethodNotAllowedException<T>(message: string, data?: T)Example:
throw new MethodNotAllowedException('DELETE method not allowed', {
requestedMethod: 'DELETE',
allowedMethods: ['GET', 'POST', 'PUT']
});Types and Interfaces
ExceptionStackFrameType
Represents a single frame in a parsed stack trace.
type ExceptionStackFrameType = {
functionName?: string;
fileName?: string;
lineNumber?: number;
columnNumber?: number;
source: string;
};IException<T>
Interface defining the exception contract.
interface IException<T = unknown> {
readonly date: Date;
readonly status?: StatusCodeType;
readonly data?: Readonly<Record<string, T>>;
readonly native?: Error;
readonly message: string;
readonly name: string;
readonly stack?: string;
stackToJson(): ExceptionStackFrameType[] | null;
}Advanced Usage
Custom Exception Classes
import { Exception } from '@ooneex/exception';
import { HttpStatus } from '@ooneex/http-status';
class PaymentException extends Exception {
constructor(message: string, data: Record<string, unknown> = {}) {
super(message, {
status: HttpStatus.Code.PaymentRequired, // 402
data
});
}
}
// Usage
throw new PaymentException('Insufficient funds', {
accountBalance: 50.00,
requiredAmount: 100.00,
currency: 'USD'
});Error Serialization
import { Exception } from '@ooneex/exception';
const exception = new Exception('Process failed', {
status: 500,
data: {
processId: 'proc-123',
step: 'validation',
retryCount: 3
}
});
// Serialize for logging or API responses
const serialized = JSON.stringify({
message: exception.message,
name: exception.name,
status: exception.status,
data: exception.data,
date: exception.date,
stackFrames: exception.stackToJson()
});
console.log(serialized);Integration with Express.js
import express from 'express';
import { Exception, NotFoundException } from '@ooneex/exception';
const app = express();
app.get('/users/:id', (req, res, next) => {
const userId = req.params.id;
// Simulate user lookup
const user = findUser(userId);
if (!user) {
throw new NotFoundException('User not found', {
userId,
searchedBy: 'id'
});
}
res.json(user);
});
// Error handler
app.use((error: any, req: express.Request, res: express.Response, next: express.NextFunction) => {
if (error instanceof Exception) {
res.status(error.status || 500).json({
error: {
message: error.message,
status: error.status,
data: error.data,
timestamp: error.date
}
});
} else {
next(error);
}
});License
This project is licensed under the MIT License - see the LICENSE file for details.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
Development Setup
- Clone the repository
- Install dependencies:
bun install - Run tests:
bun run test - Build the project:
bun run build
Guidelines
- Write tests for new features
- Follow the existing code style
- Update documentation for API changes
- Ensure all tests pass before submitting PR
Made with ❤️ by the Ooneex team