# Các Pattern Xử Lý Lỗi

Comprehensive error handling patterns and conventions for GoodGo microservices including error classes, error codes, error middleware, and standardized error responses.
> Các patterns và conventions toàn diện về error handling cho GoodGo microservices bao gồm error classes, error codes, error middleware, và standardized error responses.

## Tổng Quan

Error handling is a critical aspect of building robust microservices. This guide provides comprehensive patterns and best practices for implementing consistent, maintainable error handling across all services. It covers error types, error code systems, custom error classes, error middleware, and standardized error response formats.

Error handling là khía cạnh quan trọng của việc xây dựng microservices vững chắc. Hướng dẫn này cung cấp các patterns và best practices toàn diện để implement error handling nhất quán và dễ bảo trì trên tất cả các services. Nó bao gồm các loại errors, hệ thống error codes, custom error classes, error middleware, và các định dạng error response đã được chuẩn hóa.

## Khi Nào Sử Dụng

Use these error handling patterns when:
- Implementing error handling in services, controllers, or repositories
- Creating custom error classes for specific error scenarios
- Standardizing error responses across APIs
- Handling exceptions from external services or database operations
- Implementing error middleware and global error handlers
- Debugging error scenarios and improving error messages
- Distinguishing between operational and programming errors

Sử dụng các error handling patterns này khi:
- Implement error handling trong services, controllers, hoặc repositories
- Tạo custom error classes cho các error scenarios cụ thể
- Chuẩn hóa error responses trên các APIs
- Xử lý exceptions từ external services hoặc database operations
- Implement error middleware và global error handlers
- Debug error scenarios và cải thiện error messages
- Phân biệt giữa operational errors và programming errors

## Khái Niệm Chính

### Các Loại Lỗi

#### Lỗi Vận Hành

Expected errors that occur during normal operation. These are errors that the application is designed to handle.

Các lỗi dự kiến xảy ra trong quá trình vận hành bình thường. Đây là các lỗi mà ứng dụng được thiết kế để xử lý.

**Characteristics / Đặc Điểm**:
- **Examples / Ví dụ**: Validation errors, authentication failures, resource not found, rate limiting
- **Handling / Xử Lý**: Should be handled gracefully with appropriate HTTP status codes
- **Logging / Ghi Log**: Logged as warnings (logger.warn)
- **Exposure / Tiết Lộ**: Can expose error details to clients (with caution)
- **Recovery / Phục Hồi**: Application can recover and continue operation

**Example / Ví dụ**: [`services/iam-service/src/errors/http-error.ts`](../../../services/iam-service/src/errors/http-error.ts)

#### Lỗi Lập Trình

Unexpected errors due to bugs in code. These indicate problems that need to be fixed.

Các lỗi không mong đợi do bugs trong code. Đây là các vấn đề cần được sửa.

**Characteristics / Đặc Điểm**:
- **Examples / Ví dụ**: Null pointer exceptions, type errors, logic bugs, undefined behavior
- **Handling / Xử Lý**: Should be logged with full details for debugging
- **Logging / Ghi Log**: Logged as errors (logger.error)
- **Exposure / Tiết Lộ**: Should return generic error messages to clients (hide implementation details)
- **Recovery / Phục Hồi**: May require application restart or code fixes

### Luồng Lan Truyền Lỗi / Error Propagation Flow

Sơ đồ sau minh họa cách lỗi lan truyền qua các lớp của ứng dụng:

```mermaid
flowchart TD
    A[Request] --> B[Controller]
    B --> C[Service Layer]
    C --> D[Repository Layer]
    D --> E{Error Occurs?}
    E -->|Yes| F[Throw HttpError]
    E -->|No| G[Return Data]
    F --> H[Error Middleware]
    H --> I{Error Type?}
    I -->|HttpError| J[Extract Status/Code]
    I -->|Prisma Error| K[Map to HttpError]
    I -->|Zod Error| L[Map to ValidationError]
    I -->|Unknown| M[Map to InternalServerError]
    J --> N[Log Error]
    K --> N
    L --> N
    M --> N
    N --> O{Is Operational?}
    O -->|Yes| P[Log as Warning]
    O -->|No| Q[Log as Error]
    P --> R[Format Response]
    Q --> R
    R --> S{Is Production?}
    S -->|Yes & 5xx| T[Generic Message]
    S -->|No or < 5xx| U[Detailed Message]
    T --> V[Send Response]
    U --> V
    G --> V
```

### Cấu Trúc Phân Cấp Lỗi / Error Hierarchy Structure

Phân cấp lớp lỗi cho thấy mối quan hệ giữa các loại lỗi khác nhau:

```mermaid
classDiagram
    class Error {
        <<built-in>>
        +message: string
        +stack: string
    }
    class HttpError {
        +statusCode: number
        +errorCode: string
        +isOperational: boolean
        +details?: any
        +toApiResponse()
    }
    class NotFoundError {
        +statusCode: 404
    }
    class BadRequestError {
        +statusCode: 400
    }
    class ValidationError {
        +statusCode: 422
    }
    class UnauthorizedError {
        +statusCode: 401
    }
    class ForbiddenError {
        +statusCode: 403
    }
    class ConflictError {
        +statusCode: 409
    }
    class RateLimitError {
        +statusCode: 429
    }
    class InternalServerError {
        +statusCode: 500
    }
    class ServiceUnavailableError {
        +statusCode: 503
    }
    class DatabaseError {
        +statusCode: 500
    }
    class ExternalServiceError {
        +statusCode: 502
    }
    
    Error <|-- HttpError
    HttpError <|-- NotFoundError
    HttpError <|-- BadRequestError
    HttpError <|-- ValidationError
    HttpError <|-- UnauthorizedError
    HttpError <|-- ForbiddenError
    HttpError <|-- ConflictError
    HttpError <|-- RateLimitError
    HttpError <|-- InternalServerError
    HttpError <|-- ServiceUnavailableError
    HttpError <|-- DatabaseError
    HttpError <|-- ExternalServiceError
```

### Cây Quyết Định Xử Lý Lỗi / Error Handling Decision Tree

Sử dụng cây quyết định này để xác định lớp lỗi nào cần sử dụng:

```mermaid
flowchart TD
    A[Error Occurs] --> B{Error Type?}
    B -->|Resource Not Found| C[NotFoundError<br/>404]
    B -->|Invalid Input| D{Validation?}
    B -->|Authentication| E{Type?}
    B -->|Resource Conflict| F[ConflictError<br/>409]
    B -->|Rate Limit| G[RateLimitError<br/>429]
    B -->|Database| H[DatabaseError<br/>500]
    B -->|External Service| I[ExternalServiceError<br/>502]
    B -->|Service Unavailable| J[ServiceUnavailableError<br/>503]
    B -->|Unknown/Programming| K[InternalServerError<br/>500]
    D -->|Schema Validation| L[ValidationError<br/>422]
    D -->|Bad Request Format| M[BadRequestError<br/>400]
    E -->|No Token/Invalid| N[UnauthorizedError<br/>401]
    E -->|No Permission| O[ForbiddenError<br/>403]
    C --> P[Set isOperational: true]
    L --> P
    M --> P
    N --> P
    O --> P
    F --> P
    G --> P
    H --> Q{Is Operational?}
    I --> Q
    J --> Q
    K --> R[Set isOperational: false]
    Q -->|Yes| P
    Q -->|No| R
    P --> S[Include Error Code]
    R --> S
    S --> T[Add Context Details]
    T --> U[Throw Error]
```

### Hệ Thống Error Codes

The platform uses a centralized error code system that provides unique identifiers for each error type, enables error tracking and analytics, and supports consistent error handling.

Nền tảng sử dụng hệ thống error codes tập trung cung cấp unique identifiers cho mỗi loại lỗi, cho phép error tracking và analytics, và hỗ trợ error handling nhất quán.

**Error Code Format / Định Dạng Error Code**: `{CATEGORY}_{NUMBER}`
- `AUTH_001` - Authentication errors / Lỗi xác thực
- `VALIDATION_001` - Validation errors / Lỗi validation
- `RESOURCE_001` - Resource errors / Lỗi tài nguyên
- `DB_001` - Database errors / Lỗi database
- `SYS_001` - System errors / Lỗi hệ thống

**Tham Khảo**: [`services/iam-service/src/errors/error-codes.ts`](../../../services/iam-service/src/errors/error-codes.ts)

## Patterns

### Class Lỗi Cơ Sở

**HttpError** là base class cho tất cả custom errors:

```typescript
export class HttpError extends Error {
  public readonly statusCode: number;
  public readonly errorCode: string;
  public readonly isOperational: boolean;
  public readonly details?: any;

  constructor(
    message: string,
    statusCode: number = 500,
    errorCode: string = 'INTERNAL_ERROR',
    isOperational: boolean = true,
    details?: any
  ) {
    super(message);
    this.statusCode = statusCode;
    this.errorCode = errorCode;
    this.isOperational = isOperational;
    this.details = details;
    Error.captureStackTrace(this, this.constructor);
  }

  toApiResponse() {
    return {
      success: false,
      error: {
        code: this.errorCode,
        message: this.message,
        ...(this.details && { details: this.details }),
      },
      timestamp: new Date().toISOString(),
    };
  }
}
```

### Các Class Lỗi Chuẩn

**Resource Errors / Lỗi Tài Nguyên**:
- `NotFoundError` - 404: Resource not found / Tài nguyên không tìm thấy
- `ConflictError` - 409: Resource conflict / Xung đột tài nguyên (ví dụ: trùng lặp)
- `BadRequestError` - 400: Invalid request / Yêu cầu không hợp lệ

**Validation Errors / Lỗi Validation**:
- `ValidationError` - 422: Input validation failed / Validation đầu vào thất bại

**Authentication/Authorization / Xác Thực/Phân Quyền**:
- `UnauthorizedError` - 401: Authentication required / Yêu cầu xác thực
- `ForbiddenError` - 403: Access denied / Truy cập bị từ chối

**System Errors / Lỗi Hệ Thống**:
- `InternalServerError` - 500: Internal server error / Lỗi máy chủ nội bộ (programming error)
- `ServiceUnavailableError` - 503: Service temporarily unavailable / Dịch vụ tạm thời không khả dụng
- `DatabaseError` - 500: Database operation failed / Thao tác database thất bại
- `ExternalServiceError` - 502: External service error / Lỗi dịch vụ bên ngoài

**Rate Limiting / Giới Hạn Tốc Độ**:
- `RateLimitError` - 429: Too many requests / Quá nhiều yêu cầu

### Sử Dụng Errors Trong Services

```typescript
import { NotFoundError, ConflictError } from '../errors/http-error';

export class UserService {
  async getUserById(id: string) {
    const user = await this.repository.findById(id);
    
    if (!user) {
      throw new NotFoundError('User', { id });
    }
    
    return user;
  }
  
  async createUser(data: CreateUserInput) {
    const existing = await this.repository.findByEmail(data.email);
    
    if (existing) {
      throw new ConflictError('User with this email already exists');
    }
    
    return await this.repository.create(data);
  }
}
```

**Tham Khảo**: [`services/iam-service/src/modules/feature/feature.service.ts`](../../../services/iam-service/src/modules/feature/feature.service.ts)

### Pattern Error Middleware

Global error handler middleware xử lý tất cả errors:

```typescript
export const errorHandler = (
  err: any,
  req: express.Request,
  res: express.Response,
  _next: express.NextFunction
): void => {
  let statusCode = 500;
  let errorCode = ErrorCode.INTERNAL_ERROR;
  let message = 'Internal server error';
  let isOperational = false;
  
  // Handle HttpError instances
  if (err instanceof HttpError) {
    statusCode = err.statusCode;
    errorCode = err.errorCode as ErrorCode;
    message = err.message;
    isOperational = err.isOperational;
  }
  // Handle Prisma errors
  else if (err.code === 'P2002') {
    statusCode = 409;
    errorCode = ErrorCode.CONSTRAINT_VIOLATION;
    message = 'Resource already exists';
    isOperational = true;
  }
  // Handle Zod validation errors
  else if (err.name === 'ZodError') {
    statusCode = 422;
    errorCode = ErrorCode.VALIDATION_ERROR;
    message = 'Validation failed';
  }
  
  // Log and respond...
};
```

**Tham Khảo**: [`services/iam-service/src/middlewares/error.middleware.ts`](../../../services/iam-service/src/middlewares/error.middleware.ts)

### Wrapper Lỗi Async

Wrap async route handlers để catch promise rejections:

```typescript
export const asyncHandler = (fn: Function) => {
  return (req: express.Request, res: express.Response, next: express.NextFunction) => {
    Promise.resolve(fn(req, res, next)).catch(next);
  };
};

// Usage
router.get('/users/:id', asyncHandler(async (req, res) => {
  const user = await userService.getUserById(req.params.id);
  res.json({ success: true, data: user });
}));
```

### Định Dạng Error Response

Định dạng error response đã được chuẩn hóa:

```typescript
{
  success: false,
  error: {
    code: "RESOURCE_001",
    message: "User not found",
    details?: {
      // Optional additional details (not in production for 5xx errors)
    }
  },
  timestamp: "2024-01-01T00:00:00.000Z"
}
```

## Thực Hành Tốt Nhất

1. **Use Specific Error Classes / Sử Dụng Error Classes Cụ Thể**: Sử dụng error class cụ thể nhất cho scenario
2. **Include Context / Bao Gồm Context**: Cung cấp error messages hữu ích với context liên quan (resource IDs, field names)
3. **Mark Operational Errors / Đánh Dấu Operational Errors**: Set `isOperational: true` cho các lỗi dự kiến có thể xử lý gracefully
4. **Don't Expose Internal Details / Không Tiết Lộ Chi Tiết Nội Bộ**: Ẩn implementation details trong production (stack traces, internal paths)
5. **Log Appropriately / Log Phù Hợp**: Sử dụng `logger.error()` cho programming errors, `logger.warn()` cho operational errors
6. **Handle Database Errors / Xử Lý Database Errors**: Map Prisma errors (P2002, P2025, etc.) sang HTTP errors phù hợp
7. **Use Error Codes / Sử Dụng Error Codes**: Luôn sử dụng `ErrorCode` enum để nhất quán trên các services
8. **Validate Early / Validate Sớm**: Validate input sớm trong request pipeline để catch errors trước khi xử lý
9. **Error Middleware Order / Thứ Tự Error Middleware**: Đặt error middleware cuối cùng, sau tất cả routes
10. **Async Error Handling / Xử Lý Lỗi Async**: Luôn sử dụng `asyncHandler` cho async route handlers

## Lỗi Thường Gặp

1. **Not Using Error Classes / Không Sử Dụng Error Classes**: Sử dụng generic `Error` thay vì specific error classes như `NotFoundError`
2. **Exposing Stack Traces / Tiết Lộ Stack Traces**: Bao gồm stack traces trong production API responses
3. **Ignoring Errors / Bỏ Qua Lỗi**: Không xử lý errors trong async operations, để chúng propagate unhandled
4. **Generic Error Messages / Error Messages Chung Chung**: Sử dụng error messages mơ hồ không có context (ví dụ: "Error occurred")
5. **Not Logging / Không Log**: Quên log errors để debug và monitor
6. **Wrong HTTP Status Codes / HTTP Status Codes Sai**: Sử dụng status codes sai cho error types (ví dụ: 500 cho validation errors)
7. **Not Using Error Middleware / Không Sử Dụng Error Middleware**: Xử lý errors manually trong mỗi controller thay vì sử dụng middleware
8. **Not Marking Operational Errors / Không Đánh Dấu Operational Errors**: Không set `isOperational` flag, khiến tất cả errors bị coi như programming errors
9. **Inconsistent Error Codes / Error Codes Không Nhất Quán**: Không sử dụng centralized `ErrorCode` enum, dẫn đến error codes không nhất quán
10. **Error Details in Production / Chi Tiết Lỗi Trong Production**: Tiết lộ error details (như database queries) trong production responses

## Xử Lý Sự Cố

### Lỗi Không Được Catch Bởi Middleware

**Problem / Vấn Đề**: Error không được catch bởi error middleware và gây unhandled promise rejection

**Solution / Giải Pháp**: 
- Đảm bảo error middleware được thêm cuối cùng trong middleware chain (sau tất cả routes)
- Sử dụng `asyncHandler` wrapper cho async route handlers
- Verify error đang được throw (không chỉ log)

**Example / Ví Dụ**:
```typescript
// ❌ Bad: Error not caught
app.get('/users/:id', async (req, res) => {
  const user = await userService.getUserById(req.params.id);
  res.json(user);
});

// ✅ Good: Error caught by middleware
app.get('/users/:id', asyncHandler(async (req, res) => {
  const user = await userService.getUserById(req.params.id);
  res.json(user);
}));
```

### Error Messages Chung Chung Trong Production

**Problem / Vấn Đề**: Generic "Internal server error" được hiển thị ngay cả cho operational errors nên hiển thị messages cụ thể

**Solution / Giải Pháp**: 
- Kiểm tra `isOperational` flag được set đúng trên error instances
- Verify error middleware xử lý tất cả error types đúng cách
- Đảm bảo production environment check hoạt động đúng

### Error Code Không Tìm Thấy

**Problem / Vấn Đề**: Error code không tìm thấy trong `ErrorCode` enum, gây vấn đề mapping

**Solution / Giải Pháp**: 
- Thêm error code vào `ErrorCode` enum theo naming convention (`{CATEGORY}_{NUMBER}`)
- Update `ERROR_CODE_TO_STATUS` mapping để bao gồm error code mới
- Đảm bảo error code được sử dụng nhất quán trên các services

### Stack Traces Bị Tiết Lộ

**Problem / Vấn Đề**: Stack traces hiển thị trong API responses, tiết lộ internal implementation details

**Solution / Giải Pháp**: 
- Đảm bảo production environment checks được đặt trong error middleware
- Verify `isProduction` flag được set đúng
- Filter stack traces và internal error details trong production responses

### Prisma Errors Không Được Xử Lý

**Problem / Vấn Đề**: Prisma errors (như unique constraint violations) không được map sang HTTP errors phù hợp

**Solution / Giải Pháp**:
- Thêm Prisma error code handling trong error middleware
- Map common Prisma error codes (P2002, P2025, etc.) sang HTTP errors phù hợp
- Tham khảo Prisma error code documentation để có mapping đầy đủ

## Tài Nguyên

- [Error Classes](../../../services/iam-service/src/errors/http-error.ts) - Base error classes và implementations
- [Error Codes](../../../services/iam-service/src/errors/error-codes.ts) - Centralized error code definitions
- [Error Middleware](../../../services/iam-service/src/middlewares/error.middleware.ts) - Global error handler implementation
- [API Design](./api-design.md) - API response formats và standards
- [Security](./security.md) - Security-related error handling
- [Testing Patterns](./testing-patterns.md) - Testing error scenarios
