Python
```python
from dataclasses import dataclass, field
from typing import Optional, Dict, Any
from enum import Enum
class ErrorCode(str, Enum):
"""Standardized error codes for API responses."""
# Authentication
AUTH_INVALID_CREDENTIALS = "AUTH_INVALID_CREDENTIALS"
AUTH_TOKEN_EXPIRED = "AUTH_TOKEN_EXPIRED"
AUTH_TOKEN_INVALID = "AUTH_TOKEN_INVALID"
AUTH_EMAIL_EXISTS = "AUTH_EMAIL_EXISTS"
# Authorization
FORBIDDEN = "FORBIDDEN"
# Resources
RESOURCE_NOT_FOUND = "RESOURCE_NOT_FOUND"
RESOURCE_CONFLICT = "RESOURCE_CONFLICT"
# Rate Limiting
RATE_LIMIT_EXCEEDED = "RATE_LIMIT_EXCEEDED"
# External Services
GENERATION_FAILED = "GENERATION_FAILED"
GENERATION_TIMEOUT = "GENERATION_TIMEOUT"
# Validation
VALIDATION_ERROR = "VALIDATION_ERROR"
INVALID_STATE_TRANSITION = "INVALID_STATE_TRANSITION"
@dataclass
class BaseAppError(Exception):
"""Base exception for all application errors."""
message: str
code: ErrorCode
status_code: int = 500
details: Optional[Dict[str, Any]] = field(default_factory=dict)
retry_after: Optional[int] = None
def __post_init__(self):
super().__init__(self.message)
def to_dict(self) -> Dict[str, Any]:
"""Convert to API response format."""
error_dict = {
"error": {
"message": self.message,
"code": self.code.value,
}
}
if self.details:
error_dict["error"]["details"] = self.details
if self.retry_after is not None:
error_dict["error"]["retry_after"] = self.retry_after
return error_dict
@dataclass
class NotFoundError(BaseAppError):
"""Resource not found error."""
resource_type: str = "resource"
resource_id: str = ""
message: str = field(init=False)
code: ErrorCode = field(default=ErrorCode.RESOURCE_NOT_FOUND)
status_code: int = 404
def __post_init__(self):
self.message = f"{self.resource_type.title()} not found"
self.details = {
"resource_type": self.resource_type,
"resource_id": self.resource_id,
}
super().__post_init__()
@dataclass
class RateLimitError(BaseAppError):
"""Rate limit exceeded error."""
retry_after: int = 60
message: str = "Rate limit exceeded"
code: ErrorCode = field(default=ErrorCode.RATE_LIMIT_EXCEEDED)
status_code: int = 429
def __post_init__(self):
self.details = {"retry_after": self.retry_after}
super().__post_init__()
@dataclass
class InvalidStateTransitionError(BaseAppError):
"""Invalid state transition error."""
current_status: str = ""
target_status: str = ""
message: str = field(init=False)
code: ErrorCode = field(default=ErrorCode.INVALID_STATE_TRANSITION)
status_code: int = 409
def __post_init__(self):
self.message = f"Cannot transition from '{self.current_status}' to '{self.target_status}'"
self.details = {
"current_status": self.current_status,
"target_status": self.target_status,
}
super().__post_init__()
```
TypeScript
```typescript
export enum ErrorCode {
AUTH_INVALID_CREDENTIALS = 'AUTH_INVALID_CREDENTIALS',
AUTH_TOKEN_EXPIRED = 'AUTH_TOKEN_EXPIRED',
AUTH_TOKEN_INVALID = 'AUTH_TOKEN_INVALID',
FORBIDDEN = 'FORBIDDEN',
RESOURCE_NOT_FOUND = 'RESOURCE_NOT_FOUND',
RESOURCE_CONFLICT = 'RESOURCE_CONFLICT',
RATE_LIMIT_EXCEEDED = 'RATE_LIMIT_EXCEEDED',
VALIDATION_ERROR = 'VALIDATION_ERROR',
INVALID_STATE_TRANSITION = 'INVALID_STATE_TRANSITION',
}
interface ErrorDetails {
[key: string]: unknown;
}
export class BaseAppError extends Error {
constructor(
public readonly message: string,
public readonly code: ErrorCode,
public readonly statusCode: number = 500,
public readonly details: ErrorDetails = {},
public readonly retryAfter?: number
) {
super(message);
this.name = this.constructor.name;
}
toJSON() {
const error: Record = {
message: this.message,
code: this.code,
};
if (Object.keys(this.details).length > 0) {
error.details = this.details;
}
if (this.retryAfter !== undefined) {
error.retry_after = this.retryAfter;
}
return { error };
}
}
export class NotFoundError extends BaseAppError {
constructor(resourceType: string, resourceId: string) {
super(
${resourceType.charAt(0).toUpperCase() + resourceType.slice(1)} not found,
ErrorCode.RESOURCE_NOT_FOUND,
404,
{ resource_type: resourceType, resource_id: resourceId }
);
}
}
export class RateLimitError extends BaseAppError {
constructor(retryAfter: number = 60) {
super(
'Rate limit exceeded',
ErrorCode.RATE_LIMIT_EXCEEDED,
429,
{ retry_after: retryAfter },
retryAfter
);
}
}
export class InvalidStateTransitionError extends BaseAppError {
constructor(currentStatus: string, targetStatus: string) {
super(
Cannot transition from '${currentStatus}' to '${targetStatus}',
ErrorCode.INVALID_STATE_TRANSITION,
409,
{ current_status: currentStatus, target_status: targetStatus }
);
}
}
```