exercise3.js
JavaScript/modules/module2-intermediate/code-examples/lesson6/exercise3.js
// Exercise 3: Robust Error Handling System
// This exercise demonstrates a comprehensive error handling system
console.log("=== Exercise 3: Robust Error Handling System ===");
// Error types and codes
const ERROR_TYPES = {
VALIDATION: 'VALIDATION',
AUTHENTICATION: 'AUTHENTICATION',
AUTHORIZATION: 'AUTHORIZATION',
NETWORK: 'NETWORK',
DATABASE: 'DATABASE',
BUSINESS_LOGIC: 'BUSINESS_LOGIC',
SYSTEM: 'SYSTEM'
};
const ERROR_CODES = {
// Validation codes
REQUIRED_FIELD: 'REQUIRED_FIELD',
INVALID_FORMAT: 'INVALID_FORMAT',
OUT_OF_RANGE: 'OUT_OF_RANGE',
// Authentication codes
INVALID_CREDENTIALS: 'INVALID_CREDENTIALS',
TOKEN_EXPIRED: 'TOKEN_EXPIRED',
USER_NOT_FOUND: 'USER_NOT_FOUND',
// Network codes
CONNECTION_TIMEOUT: 'CONNECTION_TIMEOUT',
SERVER_ERROR: 'SERVER_ERROR',
NOT_FOUND: 'NOT_FOUND',
// Database codes
CONNECTION_FAILED: 'CONNECTION_FAILED',
QUERY_FAILED: 'QUERY_FAILED',
CONSTRAINT_VIOLATION: 'CONSTRAINT_VIOLATION'
};
// Base error class
class AppError extends Error {
constructor(message, type, code, details = {}) {
super(message);
this.name = 'AppError';
this.type = type;
this.code = code;
this.details = details;
this.timestamp = new Date().toISOString();
this.stack = this.stack;
}
toJSON() {
return {
name: this.name,
message: this.message,
type: this.type,
code: this.code,
details: this.details,
timestamp: this.timestamp
};
}
}
// Specific error classes
class ValidationError extends AppError {
constructor(message, field, value, code = ERROR_CODES.REQUIRED_FIELD) {
super(message, ERROR_TYPES.VALIDATION, code, { field, value });
this.name = 'ValidationError';
}
}
class AuthenticationError extends AppError {
constructor(message, code = ERROR_CODES.INVALID_CREDENTIALS) {
super(message, ERROR_TYPES.AUTHENTICATION, code);
this.name = 'AuthenticationError';
}
}
class NetworkError extends AppError {
constructor(message, statusCode, url, code = ERROR_CODES.SERVER_ERROR) {
super(message, ERROR_TYPES.NETWORK, code, { statusCode, url });
this.name = 'NetworkError';
}
}
class DatabaseError extends AppError {
constructor(message, operation, table, code = ERROR_CODES.QUERY_FAILED) {
super(message, ERROR_TYPES.DATABASE, code, { operation, table });
this.name = 'DatabaseError';
}
}
// Error handler class
class ErrorHandler {
static handle(error, context = {}) {
const errorInfo = {
error: error.toJSON ? error.toJSON() : {
name: error.name,
message: error.message,
stack: error.stack
},
context: context,
timestamp: new Date().toISOString()
};
// Log error
this.logError(errorInfo);
// Determine user-friendly message
const userMessage = this.getUserMessage(error);
// Determine if error should be reported
const shouldReport = this.shouldReportError(error);
return {
success: false,
error: userMessage,
details: shouldReport ? errorInfo : null,
code: error.code || 'UNKNOWN_ERROR'
};
}
static logError(errorInfo) {
console.log(`[ERROR LOG] ${errorInfo.timestamp}`);
console.log(`Type: ${errorInfo.error.type || 'Unknown'}`);
console.log(`Message: ${errorInfo.error.message}`);
console.log(`Context:`, errorInfo.context);
console.log('---');
// In a real application, you would send this to a logging service
// or save it to a file/database
}
static getUserMessage(error) {
if (error instanceof ValidationError) {
return `Please check your input: ${error.message}`;
} else if (error instanceof AuthenticationError) {
return "Authentication failed. Please check your credentials.";
} else if (error instanceof NetworkError) {
return "Network error occurred. Please try again later.";
} else if (error instanceof DatabaseError) {
return "Database error occurred. Please contact support.";
} else {
return "An unexpected error occurred. Please try again.";
}
}
static shouldReportError(error) {
// Don't report user input validation errors
if (error instanceof ValidationError) {
return false;
}
// Report system errors
if (error instanceof DatabaseError || error instanceof NetworkError) {
return true;
}
// Report unexpected errors
if (!(error instanceof AppError)) {
return true;
}
return false;
}
}
// Retry mechanism
class RetryHandler {
static async retry(operation, maxRetries = 3, delay = 1000) {
let lastError;
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
console.log(`Attempt ${attempt}/${maxRetries}`);
return await operation();
} catch (error) {
lastError = error;
// Don't retry validation or authentication errors
if (error instanceof ValidationError || error instanceof AuthenticationError) {
throw error;
}
if (attempt < maxRetries) {
console.log(`Attempt ${attempt} failed, retrying in ${delay}ms...`);
await this.delay(delay);
delay *= 2; // Exponential backoff
}
}
}
throw lastError;
}
static delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
}
// Example application functions with error handling
class UserService {
static async createUser(userData) {
try {
// Validate user data
this.validateUserData(userData);
// Simulate database operation
const user = await this.saveUserToDatabase(userData);
return { success: true, user: user };
} catch (error) {
return ErrorHandler.handle(error, { operation: 'createUser', userData });
}
}
static validateUserData(userData) {
if (!userData) {
throw new ValidationError("User data is required", "userData", userData);
}
if (!userData.email) {
throw new ValidationError("Email is required", "email", userData.email);
}
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(userData.email)) {
throw new ValidationError("Invalid email format", "email", userData.email, ERROR_CODES.INVALID_FORMAT);
}
if (!userData.username) {
throw new ValidationError("Username is required", "username", userData.username);
}
if (userData.username.length < 3) {
throw new ValidationError("Username must be at least 3 characters", "username", userData.username, ERROR_CODES.OUT_OF_RANGE);
}
}
static async saveUserToDatabase(userData) {
// Simulate database operation with potential failures
return new Promise((resolve, reject) => {
setTimeout(() => {
const random = Math.random();
if (random < 0.3) {
reject(new DatabaseError("Database connection failed", "INSERT", "users", ERROR_CODES.CONNECTION_FAILED));
} else if (random < 0.5) {
reject(new DatabaseError("Username already exists", "INSERT", "users", ERROR_CODES.CONSTRAINT_VIOLATION));
} else {
resolve({
id: Date.now(),
...userData,
createdAt: new Date().toISOString()
});
}
}, 500);
});
}
}
class ApiService {
static async fetchUserData(userId) {
try {
const userData = await RetryHandler.retry(async () => {
return await this.makeApiRequest(`/api/users/${userId}`);
});
return { success: true, data: userData };
} catch (error) {
return ErrorHandler.handle(error, { operation: 'fetchUserData', userId });
}
}
static async makeApiRequest(url) {
// Simulate API request with potential failures
return new Promise((resolve, reject) => {
setTimeout(() => {
const random = Math.random();
if (random < 0.2) {
reject(new NetworkError("Connection timeout", 408, url, ERROR_CODES.CONNECTION_TIMEOUT));
} else if (random < 0.4) {
reject(new NetworkError("Server error", 500, url, ERROR_CODES.SERVER_ERROR));
} else if (random < 0.6) {
reject(new NetworkError("Not found", 404, url, ERROR_CODES.NOT_FOUND));
} else {
resolve({ id: 123, name: "John Doe", email: "john@example.com" });
}
}, 1000);
});
}
}
// Test the robust error handling system
console.log("=== Testing Robust Error Handling System ===");
async function runTests() {
// Test 1: User creation with validation errors
console.log("\n1. Testing User Creation with Validation Errors:");
const invalidUsers = [
null,
{ email: "invalid-email" },
{ email: "test@example.com" }, // Missing username
{ email: "test@example.com", username: "ab" } // Username too short
];
for (let i = 0; i < invalidUsers.length; i++) {
console.log(`\nTest ${i + 1}:`, invalidUsers[i]);
const result = await UserService.createUser(invalidUsers[i]);
console.log("Result:", result);
}
// Test 2: User creation with database errors
console.log("\n2. Testing User Creation with Database Errors:");
const validUser = { email: "test@example.com", username: "testuser" };
for (let i = 0; i < 3; i++) {
console.log(`\nAttempt ${i + 1}:`);
const result = await UserService.createUser(validUser);
console.log("Result:", result);
}
// Test 3: API requests with retry mechanism
console.log("\n3. Testing API Requests with Retry Mechanism:");
for (let i = 0; i < 3; i++) {
console.log(`\nAPI Test ${i + 1}:`);
const result = await ApiService.fetchUserData(123);
console.log("Result:", result);
}
}
// Run the tests
runTests().then(() => {
console.log("\n=== Robust Error Handling System Summary ===");
console.log("✓ Comprehensive error classification system");
console.log("✓ Centralized error handling and logging");
console.log("✓ User-friendly error messages");
console.log("✓ Retry mechanism with exponential backoff");
console.log("✓ Error reporting based on error type");
console.log("✓ Context-aware error handling");
}).catch(error => {
console.error("Test execution failed:", error);
});
関連記事
exercise1.js
exercise1.js — javascript source code from the JavaScript learning materials (JavaScript/modules/module1-foundations/code-examples/lesson1/exercise1.js).
記事を読む →exercise2.js
exercise2.js — javascript source code from the JavaScript learning materials (JavaScript/modules/module1-foundations/code-examples/lesson1/exercise2.js).
記事を読む →exercise3.js
exercise3.js — javascript source code from the JavaScript learning materials (JavaScript/modules/module1-foundations/code-examples/lesson1/exercise3.js).
記事を読む →hello.js
hello.js — javascript source code from the JavaScript learning materials (JavaScript/modules/module1-foundations/code-examples/lesson1/hello.js).
記事を読む →exercise1.js
exercise1.js — javascript source code from the JavaScript learning materials (JavaScript/modules/module1-foundations/code-examples/lesson2/exercise1.js).
記事を読む →exercise2.js
exercise2.js — javascript source code from the JavaScript learning materials (JavaScript/modules/module1-foundations/code-examples/lesson2/exercise2.js).
記事を読む →