Skip to content

Error Handling Guide

@mcabreradev/filter provides comprehensive error handling with custom error classes that provide detailed context and helpful messages.

Error Classes

FilterError (Base Class)

Base error class for all filter-related errors.

typescript
import { FilterError } from '@mcabreradev/filter';

try {
  // Your filter code
} catch (error) {
  if (error instanceof FilterError) {
    console.log(error.code);      // Error code
    console.log(error.context);   // Additional context
    console.log(error.toJSON());  // Serializable format
  }
}

InvalidExpressionError

Thrown when filter expression is invalid.

typescript
import { filter, InvalidExpressionError } from '@mcabreradev/filter';

try {
  filter(users, { age: { $invalidOp: 30 } });
} catch (error) {
  if (error instanceof InvalidExpressionError) {
    console.log(error.validationErrors);  // Array of validation errors
    console.log(error.context.expression); // The invalid expression
  }
}

OperatorError

Thrown when operator usage is incorrect.

typescript
import { filter, OperatorError } from '@mcabreradev/filter';

try {
  filter(users, { age: { $gt: 'not-a-number' } });
} catch (error) {
  if (error instanceof OperatorError) {
    console.log(error.operator);  // '$gt'
    console.log(error.context.value); // 'not-a-number'
  }
}

ValidationError

Thrown when validation fails.

typescript
import { validateExpression, ValidationError } from '@mcabreradev/filter';

try {
  validateExpression(invalidExpression);
} catch (error) {
  if (error instanceof ValidationError) {
    console.log(error.field);   // Field that failed
    console.log(error.errors);  // Array of error messages
  }
}

TypeMismatchError

Thrown when type mismatch occurs.

typescript
import { filter, TypeMismatchError } from '@mcabreradev/filter';

try {
  filter('not-an-array', { name: 'John' });
} catch (error) {
  if (error instanceof TypeMismatchError) {
    console.log(error.expected);  // 'array'
    console.log(error.received);  // 'string'
    console.log(error.field);     // Field name if applicable
  }
}

GeospatialError

Thrown when geospatial operation fails.

typescript
import { filter, GeospatialError } from '@mcabreradev/filter';

try {
  filter(locations, {
    location: {
      $near: {
        center: { lat: 91, lng: 200 },  // Invalid coordinates
        maxDistanceMeters: 1000
      }
    }
  });
} catch (error) {
  if (error instanceof GeospatialError) {
    console.log(error.coordinates);  // Invalid coordinates
  }
}

ConfigurationError

Thrown when configuration is invalid.

typescript
import { filter, ConfigurationError } from '@mcabreradev/filter';

try {
  filter(users, { name: 'John' }, { maxDepth: -1 });
} catch (error) {
  if (error instanceof ConfigurationError) {
    console.log(error.option);  // 'maxDepth'
  }
}

PerformanceLimitError

Thrown when performance limits are exceeded.

typescript
import { PerformanceLimitError } from '@mcabreradev/filter';

try {
  // Operation that exceeds performance limits
} catch (error) {
  if (error instanceof PerformanceLimitError) {
    console.log(error.limit);   // Performance limit
    console.log(error.actual);  // Actual value
  }
}

Error Helpers

isFilterError

Check if error is a FilterError.

typescript
import { isFilterError } from '@mcabreradev/filter';

try {
  // Your code
} catch (error) {
  if (isFilterError(error)) {
    console.log('Filter error:', error.code);
  }
}

getUserFriendlyMessage

Get user-friendly error message.

typescript
import { getUserFriendlyMessage } from '@mcabreradev/filter';

try {
  filter(users, invalidExpression);
} catch (error) {
  const friendlyMessage = getUserFriendlyMessage(error);
  // Display to user: "The filter expression is invalid. Please check the syntax and try again."
}

extractErrorDetails

Extract error details for logging.

typescript
import { extractErrorDetails } from '@mcabreradev/filter';

try {
  filter(users, expression);
} catch (error) {
  const details = extractErrorDetails(error);
  console.log({
    message: details.message,
    code: details.code,
    context: details.context,
    stack: details.stack
  });
}

wrapError

Wrap unknown errors in FilterError.

typescript
import { wrapError } from '@mcabreradev/filter';

try {
  // Third-party code
} catch (error) {
  const wrappedError = wrapError(error, { operation: 'filter' });
  throw wrappedError;
}

Error Codes

All errors have standardized error codes:

typescript
import { ErrorCodes } from '@mcabreradev/filter';

console.log(ErrorCodes.INVALID_EXPRESSION);    // 'INVALID_EXPRESSION'
console.log(ErrorCodes.OPERATOR_ERROR);        // 'OPERATOR_ERROR'
console.log(ErrorCodes.VALIDATION_ERROR);      // 'VALIDATION_ERROR'
console.log(ErrorCodes.CONFIGURATION_ERROR);   // 'CONFIGURATION_ERROR'
console.log(ErrorCodes.TYPE_MISMATCH);         // 'TYPE_MISMATCH'
console.log(ErrorCodes.GEOSPATIAL_ERROR);      // 'GEOSPATIAL_ERROR'
console.log(ErrorCodes.PERFORMANCE_LIMIT);     // 'PERFORMANCE_LIMIT'

Best Practices

1. Type-Safe Error Handling

typescript
import {
  filter,
  InvalidExpressionError,
  OperatorError,
  ValidationError
} from '@mcabreradev/filter';

try {
  const result = filter(users, expression);
} catch (error) {
  if (error instanceof InvalidExpressionError) {
    // Handle invalid expression
    console.error('Invalid expression:', error.context.expression);
  } else if (error instanceof OperatorError) {
    // Handle operator error
    console.error('Operator error:', error.operator);
  } else if (error instanceof ValidationError) {
    // Handle validation error
    console.error('Validation error:', error.errors);
  } else {
    // Handle unknown error
    console.error('Unknown error:', error);
  }
}

2. Error Logging

typescript
import { filter, extractErrorDetails } from '@mcabreradev/filter';

try {
  filter(users, expression);
} catch (error) {
  const details = extractErrorDetails(error);
  
  // Log to monitoring service
  logger.error('Filter error', {
    code: details.code,
    message: details.message,
    context: details.context,
    stack: details.stack
  });
}

3. User-Friendly Messages

typescript
import { filter, getUserFriendlyMessage } from '@mcabreradev/filter';

try {
  filter(users, expression);
} catch (error) {
  // Show friendly message to user
  toast.error(getUserFriendlyMessage(error));
  
  // Log technical details for debugging
  console.error(error);
}

4. Error Recovery

typescript
import { filter, InvalidExpressionError } from '@mcabreradev/filter';

function safeFilter<T>(array: T[], expression: unknown, fallback: T[] = []) {
  try {
    return filter(array, expression);
  } catch (error) {
    if (error instanceof InvalidExpressionError) {
      console.warn('Invalid expression, using fallback:', error.message);
      return fallback;
    }
    throw error;
  }
}

5. Validation Before Filtering

typescript
import { validateExpression, filter } from '@mcabreradev/filter';

function filterWithValidation<T>(array: T[], expression: unknown) {
  try {
    // Validate expression first
    const validated = validateExpression(expression);
    
    // Then filter
    return filter(array, validated);
  } catch (error) {
    // Handle validation errors
    console.error('Validation failed:', error);
    throw error;
  }
}

Error Serialization

All errors can be serialized to JSON:

typescript
import { filter } from '@mcabreradev/filter';

try {
  filter(users, expression);
} catch (error) {
  if (error instanceof FilterError) {
    const json = error.toJSON();
    
    // Send to API
    fetch('/api/error-report', {
      method: 'POST',
      body: JSON.stringify(json)
    });
  }
}

TypeScript Support

Full TypeScript support with type guards:

typescript
import type { FilterError } from '@mcabreradev/filter';
import { isFilterError } from '@mcabreradev/filter';

function handleError(error: unknown): void {
  if (isFilterError(error)) {
    // TypeScript knows error is FilterError
    console.log(error.code);
    console.log(error.context);
  }
}

Integration Examples

React

typescript
import { useState } from 'react';
import { filter, getUserFriendlyMessage } from '@mcabreradev/filter';

function UserList({ users }) {
  const [error, setError] = useState<string | null>(null);

  const handleFilter = (expression: unknown) => {
    try {
      const filtered = filter(users, expression);
      setError(null);
      return filtered;
    } catch (err) {
      setError(getUserFriendlyMessage(err));
      return [];
    }
  };

  return (
    <div>
      {error && <div className="error">{error}</div>}
      {/* ... */}
    </div>
  );
}

Express.js

typescript
import { filter, extractErrorDetails } from '@mcabreradev/filter';

app.post('/api/filter', (req, res) => {
  try {
    const result = filter(data, req.body.expression);
    res.json({ success: true, data: result });
  } catch (error) {
    const details = extractErrorDetails(error);
    
    res.status(400).json({
      success: false,
      error: {
        code: details.code,
        message: details.message
      }
    });
  }
});

See Also:

Released under the MIT License.