- Added request/response flow diagrams to api-design and api-gateway-advanced skills for better visualization of processes. - Introduced configuration loading flow in configuration-management skill to clarify the configuration process. - Included error propagation flow in error-handling-patterns skill to illustrate error handling across layers. - Enhanced various skills with additional diagrams to improve understanding of complex concepts. These updates aim to provide clearer guidance and improve the overall documentation experience for developers.
463 lines
16 KiB
Markdown
463 lines
16 KiB
Markdown
# Các Pattern Middleware
|
|
|
|
Express middleware patterns and best practices for GoodGo microservices including middleware chain ordering, custom middleware creation, authentication, validation, logging, and error handling middleware.
|
|
> Các patterns và best practices về Express middleware cho GoodGo microservices bao gồm thứ tự middleware chain, tạo custom middleware, authentication, validation, logging, và error handling middleware.
|
|
|
|
## Tổng Quan
|
|
|
|
Middleware functions are the fundamental building blocks of Express.js applications. They provide a way to execute code, make changes to requests and responses, end the request-response cycle, and call the next middleware. This guide covers middleware patterns, ordering, common middleware implementations, and best practices for GoodGo microservices.
|
|
|
|
Middleware functions là các building blocks cơ bản của ứng dụng Express.js. Chúng cung cấp cách để thực thi code, thay đổi requests và responses, kết thúc request-response cycle, và gọi middleware tiếp theo. Hướng dẫn này bao gồm các middleware patterns, thứ tự, common middleware implementations, và best practices cho GoodGo microservices.
|
|
|
|
## Khi Nào Sử Dụng
|
|
|
|
Use middleware patterns when:
|
|
- Creating custom Express middleware
|
|
- Organizing middleware chains and ordering
|
|
- Implementing authentication/authorization middleware
|
|
- Creating request/response transformation middleware
|
|
- Handling cross-cutting concerns (logging, metrics, validation)
|
|
- Implementing async middleware patterns
|
|
- Testing middleware implementations
|
|
|
|
Sử dụng middleware patterns khi:
|
|
- Tạo custom Express middleware
|
|
- Tổ chức middleware chains và thứ tự
|
|
- Implement authentication/authorization middleware
|
|
- Tạo request/response transformation middleware
|
|
- Xử lý cross-cutting concerns (logging, metrics, validation)
|
|
- Implement async middleware patterns
|
|
- Testing middleware implementations
|
|
|
|
## Khái Niệm Chính
|
|
|
|
### Chữ Ký Function Middleware
|
|
|
|
Express middleware functions have a specific signature that receives request, response, and next function.
|
|
|
|
Express middleware functions có chữ ký cụ thể nhận request, response, và next function.
|
|
|
|
```typescript
|
|
(req: Request, res: Response, next: NextFunction) => void | Promise<void>
|
|
```
|
|
|
|
### Các Loại Middleware
|
|
|
|
1. **Application-level / Cấp Ứng Dụng**: Applied to all routes (`app.use()`)
|
|
2. **Router-level / Cấp Router**: Applied to specific routes (`router.use()`)
|
|
3. **Route-level / Cấp Route**: Applied to specific route handlers
|
|
|
|
### Thứ Tự Thực Thi Middleware
|
|
|
|
Middleware order is critical! Execution flows top-to-bottom in the order they are registered.
|
|
|
|
Thứ tự middleware rất quan trọng! Thực thi theo trình tự từ trên xuống dưới theo thứ tự đăng ký.
|
|
|
|
```
|
|
Request → Middleware 1 → Middleware 2 → ... → Route Handler → Response
|
|
```
|
|
|
|
Biểu đồ sau minh họa luồng middleware chain hoàn chỉnh trong GoodGo services:
|
|
|
|
The following diagram illustrates the complete middleware chain flow in GoodGo services:
|
|
|
|
```mermaid
|
|
flowchart TD
|
|
Start([HTTP Request]) --> Security["Security Middleware<br/>Helmet, CORS"]
|
|
Security --> RateLimit["Rate Limiting<br/>Middleware"]
|
|
RateLimit --> Correlation["Correlation ID<br/>Middleware"]
|
|
Correlation --> BodyParsing["Body Parsing<br/>JSON, URLEncoded, Cookies"]
|
|
BodyParsing --> Logging["Request Logging<br/>Middleware"]
|
|
Logging --> Metrics["Metrics Collection<br/>Middleware"]
|
|
Metrics --> Routes["Route Handlers"]
|
|
Routes -->|Success| Response([HTTP Response])
|
|
Routes -->|Error| ErrorHandler["Error Handler<br/>Middleware"]
|
|
Routes -->|Not Found| NotFound["Not Found<br/>Handler"]
|
|
ErrorHandler --> Response
|
|
NotFound --> Response
|
|
```
|
|
|
|
## Patterns
|
|
|
|
### Thứ Tự Middleware Chain
|
|
|
|
Standard middleware order in GoodGo services ensures proper request processing flow.
|
|
|
|
Thứ tự middleware chuẩn trong GoodGo services đảm bảo luồng xử lý request đúng cách.
|
|
|
|
```typescript
|
|
// Bảo mật
|
|
app.use(helmet());
|
|
app.use(cors({ ... }));
|
|
|
|
// Giới hạn tốc độ
|
|
app.use('/api', rateLimitMiddleware);
|
|
|
|
// Correlation ID (sớm cho tracing)
|
|
app.use(correlationMiddleware());
|
|
|
|
// Phân tích body
|
|
app.use(express.json());
|
|
app.use(express.urlencoded({ extended: true }));
|
|
app.use(cookieParser());
|
|
|
|
// Ghi log request
|
|
app.use(loggerMiddleware);
|
|
|
|
// Metrics
|
|
app.use(metricsMiddleware);
|
|
|
|
// Routes
|
|
app.use(createRouter());
|
|
|
|
// Xử lý lỗi (LUÔN CUỐI CÙNG)
|
|
app.use(notFoundHandler);
|
|
app.use(errorHandler);
|
|
```
|
|
|
|
**Tham Khảo**: [`services/iam-service/src/main.ts`](../../../services/iam-service/src/main.ts)
|
|
|
|
### Pattern Correlation Middleware
|
|
|
|
Adds correlation ID for request tracing across services.
|
|
|
|
Thêm correlation ID để tracing requests qua các services.
|
|
|
|
```typescript
|
|
export const correlationMiddleware = () => {
|
|
return (req: Request, res: Response, next: NextFunction) => {
|
|
const correlationId = req.headers['x-correlation-id'] || generateId();
|
|
req.correlationId = correlationId;
|
|
res.setHeader('x-correlation-id', correlationId);
|
|
next();
|
|
};
|
|
};
|
|
```
|
|
|
|
**Tham Khảo**: [`services/iam-service/src/middlewares/correlation.middleware.ts`](../../../services/iam-service/src/middlewares/correlation.middleware.ts)
|
|
|
|
### Pattern Authentication Middleware
|
|
|
|
Verifies JWT tokens and attaches user information to request.
|
|
|
|
Xác minh JWT tokens và gắn thông tin người dùng vào request.
|
|
|
|
```typescript
|
|
export const authenticate = () => {
|
|
return async (req: Request, res: Response, next: NextFunction) => {
|
|
try {
|
|
const token = extractToken(req);
|
|
if (!token) {
|
|
return res.status(401).json({ error: 'Unauthorized' });
|
|
}
|
|
|
|
const payload = await jwtService.verify(token);
|
|
req.user = payload;
|
|
next();
|
|
} catch (error) {
|
|
return res.status(401).json({ error: 'Invalid token' });
|
|
}
|
|
};
|
|
};
|
|
```
|
|
|
|
Biểu đồ tuần tự sau minh họa luồng authentication middleware:
|
|
|
|
The following sequence diagram illustrates the authentication middleware flow:
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
participant Client
|
|
participant AuthMW as Authentication Middleware
|
|
participant JWTService as JWT Service
|
|
participant RouteHandler as Route Handler
|
|
|
|
Client->>AuthMW: HTTP Request with Token
|
|
AuthMW->>AuthMW: Extract token from headers
|
|
alt Token exists
|
|
AuthMW->>JWTService: Verify token
|
|
alt Token valid
|
|
JWTService-->>AuthMW: Payload (user data)
|
|
AuthMW->>AuthMW: Attach user to req.user
|
|
AuthMW->>RouteHandler: next() - Continue
|
|
RouteHandler->>Client: HTTP Response (200)
|
|
else Token invalid
|
|
JWTService-->>AuthMW: Verification error
|
|
AuthMW->>Client: HTTP Response (401 Unauthorized)
|
|
end
|
|
else No token
|
|
AuthMW->>Client: HTTP Response (401 Unauthorized)
|
|
end
|
|
```
|
|
|
|
**Tham Khảo**: [`services/iam-service/src/middlewares/auth.middleware.ts`](../../../services/iam-service/src/middlewares/auth.middleware.ts)
|
|
|
|
### Pattern Validation Middleware
|
|
|
|
Validates request data using Zod schemas.
|
|
|
|
Validate dữ liệu request sử dụng Zod schemas.
|
|
|
|
```typescript
|
|
export const validateDto = (schema: AnyZodObject, property: 'body' | 'query' | 'params' = 'body') => {
|
|
return (req: Request, res: Response, next: NextFunction) => {
|
|
try {
|
|
const validatedData = schema.parse(req[property]);
|
|
(req as any)[property] = validatedData;
|
|
next();
|
|
} catch (error) {
|
|
if (error instanceof ZodError) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
error: {
|
|
code: 'VALIDATION_ERROR',
|
|
details: error.errors,
|
|
},
|
|
});
|
|
}
|
|
next(error);
|
|
}
|
|
};
|
|
};
|
|
```
|
|
|
|
Biểu đồ tuần tự sau minh họa luồng validation middleware:
|
|
|
|
The following sequence diagram shows the validation middleware flow:
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
participant Client
|
|
participant ValidateMW as Validation Middleware
|
|
participant ZodSchema as Zod Schema
|
|
participant RouteHandler as Route Handler
|
|
|
|
Client->>ValidateMW: HTTP Request with Data
|
|
ValidateMW->>ValidateMW: Extract data from req[property]
|
|
ValidateMW->>ZodSchema: schema.parse(data)
|
|
alt Validation successful
|
|
ZodSchema-->>ValidateMW: Validated data
|
|
ValidateMW->>ValidateMW: Replace req[property] with validated data
|
|
ValidateMW->>RouteHandler: next() - Continue
|
|
RouteHandler->>Client: HTTP Response (200)
|
|
else Validation failed
|
|
ZodSchema-->>ValidateMW: ZodError with details
|
|
ValidateMW->>ValidateMW: Format error response
|
|
ValidateMW->>Client: HTTP Response (400 Validation Error)
|
|
end
|
|
```
|
|
|
|
**Tham Khảo**: [`services/iam-service/src/middlewares/validation.middleware.ts`](../../../services/iam-service/src/middlewares/validation.middleware.ts)
|
|
|
|
### Pattern Async Middleware
|
|
|
|
Handle async operations properly to catch promise rejections.
|
|
|
|
Xử lý async operations đúng cách để catch promise rejections.
|
|
|
|
```typescript
|
|
export const asyncHandler = (fn: Function) => {
|
|
return (req: Request, res: Response, next: NextFunction) => {
|
|
Promise.resolve(fn(req, res, next)).catch(next);
|
|
};
|
|
};
|
|
|
|
// Usage
|
|
app.get('/users', asyncHandler(async (req, res) => {
|
|
const users = await userService.findAll();
|
|
res.json({ success: true, data: users });
|
|
}));
|
|
```
|
|
|
|
Biểu đồ tuần tự sau minh họa xử lý lỗi async middleware:
|
|
|
|
The following sequence diagram illustrates async middleware error handling:
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
participant Client
|
|
participant AsyncMW as Async Middleware Wrapper
|
|
participant AsyncHandler as Async Route Handler
|
|
participant ErrorHandler as Error Handler
|
|
|
|
Client->>AsyncMW: HTTP Request
|
|
AsyncMW->>AsyncHandler: Execute async function
|
|
alt Async operation succeeds
|
|
AsyncHandler->>AsyncHandler: Process request
|
|
AsyncHandler->>Client: HTTP Response (200)
|
|
else Async operation fails
|
|
AsyncHandler-->>AsyncMW: Promise rejection (Error)
|
|
AsyncMW->>ErrorHandler: next(error)
|
|
ErrorHandler->>ErrorHandler: Format error response
|
|
ErrorHandler->>Client: HTTP Response (500 Error)
|
|
end
|
|
```
|
|
|
|
### Pattern Logging Middleware
|
|
|
|
Log request details with timing and correlation tracking.
|
|
|
|
Ghi log chi tiết request với timing và correlation tracking.
|
|
|
|
```typescript
|
|
export const requestLogger = (req: Request, res: Response, next: NextFunction) => {
|
|
const startTime = Date.now();
|
|
|
|
res.on('finish', () => {
|
|
const duration = Date.now() - startTime;
|
|
logger.info('Request completed', {
|
|
method: req.method,
|
|
url: req.url,
|
|
statusCode: res.statusCode,
|
|
duration,
|
|
correlationId: req.correlationId,
|
|
});
|
|
});
|
|
|
|
next();
|
|
};
|
|
```
|
|
|
|
Biểu đồ tuần tự sau minh họa cách logging middleware theo dõi vòng đời request:
|
|
|
|
The following sequence diagram illustrates how logging middleware tracks request lifecycle:
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
participant Client
|
|
participant LogMW as Logging Middleware
|
|
participant RouteHandler as Route Handler
|
|
participant Logger as Logger Service
|
|
participant Response as Response Object
|
|
|
|
Client->>LogMW: HTTP Request
|
|
LogMW->>LogMW: Record startTime = Date.now()
|
|
LogMW->>RouteHandler: next() - Continue chain
|
|
|
|
RouteHandler->>RouteHandler: Process request
|
|
RouteHandler->>Response: res.json(data) or res.send()
|
|
|
|
Response->>Response: Set statusCode, send response
|
|
Response->>Response: Emit 'finish' event
|
|
|
|
Response->>LogMW: 'finish' event triggered
|
|
LogMW->>LogMW: Calculate duration = Date.now() - startTime
|
|
LogMW->>Logger: logger.info('Request completed', {<br/>method, url, statusCode,<br/>duration, correlationId})
|
|
Logger->>Logger: Write structured log entry
|
|
|
|
Response->>Client: HTTP Response
|
|
```
|
|
|
|
### Chuyển Đổi Request/Response
|
|
|
|
Transform request or response data in middleware.
|
|
|
|
Chuyển đổi dữ liệu request hoặc response trong middleware.
|
|
|
|
```typescript
|
|
export const transformResponse = () => {
|
|
return (req: Request, res: Response, next: NextFunction) => {
|
|
const originalJson = res.json.bind(res);
|
|
|
|
res.json = function(data: any) {
|
|
const transformed = {
|
|
success: true,
|
|
data,
|
|
timestamp: new Date().toISOString(),
|
|
};
|
|
return originalJson(transformed);
|
|
};
|
|
|
|
next();
|
|
};
|
|
};
|
|
```
|
|
|
|
Biểu đồ tuần tự sau minh họa cách middleware chuyển đổi request và response hoạt động:
|
|
|
|
The following sequence diagram shows how request and response transformation middleware works:
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
participant Client
|
|
participant TransformMW as Transform Middleware
|
|
participant RouteHandler as Route Handler
|
|
participant Response as Response Object
|
|
|
|
Client->>TransformMW: HTTP Request
|
|
Note over TransformMW: Intercept res.json()
|
|
TransformMW->>TransformMW: Store original res.json
|
|
TransformMW->>TransformMW: Override res.json with transformation logic
|
|
TransformMW->>RouteHandler: next() - Continue chain
|
|
|
|
RouteHandler->>RouteHandler: Process request, Generate data
|
|
RouteHandler->>Response: res.json(rawData)
|
|
|
|
Note over Response: Transformed res.json executes
|
|
Response->>Response: Wrap data: success, data, timestamp
|
|
Response->>Client: HTTP Response (transformed)
|
|
```
|
|
|
|
## Thực Hành Tốt Nhất
|
|
|
|
1. **Order Matters / Thứ Tự Quan Trọng**: Đặt middleware đúng thứ tự (security → correlation → parsing → logging → routes → errors)
|
|
2. **Error Handling / Xử Lý Lỗi**: Luôn xử lý errors và gọi `next(error)` cho error middleware
|
|
3. **Async Support / Hỗ Trợ Async**: Wrap async middleware đúng cách để catch promise rejections
|
|
4. **Early Returns / Return Sớm**: Sử dụng early returns cho validation failures (không gọi `next()`)
|
|
5. **Request Extension / Mở Rộng Request**: Sử dụng TypeScript declaration merging để mở rộng Request type
|
|
6. **Conditional Logic / Logic Có Điều Kiện**: Sử dụng middleware factories cho conditional middleware
|
|
7. **Reusability / Tái Sử Dụng**: Tạo reusable middleware functions
|
|
8. **Performance / Hiệu Suất**: Giữ middleware lightweight, tránh heavy operations
|
|
|
|
## Lỗi Thường Gặp
|
|
|
|
1. **Wrong Order / Thứ Tự Sai**: Đặt middleware sai thứ tự (ví dụ: error handler trước routes)
|
|
2. **Not Calling Next / Không Gọi Next**: Quên gọi `next()` hoặc `next(error)`
|
|
3. **Async Errors / Lỗi Async**: Không xử lý promise rejections trong async middleware
|
|
4. **Early Return Issues / Vấn Đề Return Sớm**: Gọi `next()` sau khi đã send response
|
|
5. **Type Safety / An Toàn Kiểu**: Không mở rộng Express Request type đúng cách
|
|
6. **Performance / Hiệu Suất**: Thực hiện heavy operations trong middleware
|
|
|
|
## Xử Lý Sự Cố
|
|
|
|
### Middleware Không Thực Thi
|
|
|
|
**Problem / Vấn Đề**: Middleware không được gọi
|
|
|
|
**Solution / Giải Pháp**:
|
|
- Kiểm tra thứ tự middleware, đảm bảo nó được thêm trước routes
|
|
- Verify `next()` được gọi
|
|
- Check middleware registration order
|
|
|
|
### Lỗi Async Không Được Bắt
|
|
|
|
**Problem / Vấn Đề**: Unhandled promise rejections trong async middleware
|
|
|
|
**Solution / Giải Pháp**:
|
|
- Sử dụng `asyncHandler` wrapper
|
|
- Hoặc wrap async code trong try-catch với `next(error)`
|
|
|
|
**Example / Ví Dụ**:
|
|
```typescript
|
|
// ❌ Bad: Unhandled promise rejection
|
|
app.get('/users', async (req, res) => {
|
|
const users = await userService.findAll(); // Error not caught!
|
|
res.json(users);
|
|
});
|
|
|
|
// ✅ Good: Proper error handling
|
|
app.get('/users', asyncHandler(async (req, res) => {
|
|
const users = await userService.findAll();
|
|
res.json(users);
|
|
}));
|
|
```
|
|
|
|
## Tài Nguyên
|
|
|
|
- [Correlation Middleware](../../../services/iam-service/src/middlewares/correlation.middleware.ts) - Correlation ID implementation
|
|
- [Auth Middleware](../../../services/iam-service/src/middlewares/auth.middleware.ts) - Authentication middleware
|
|
- [Validation Middleware](../../../services/iam-service/src/middlewares/validation.middleware.ts) - Request validation
|
|
- [Error Middleware](../../../services/iam-service/src/middlewares/error.middleware.ts) - Error handling
|
|
- [Metrics Middleware](../../../services/iam-service/src/middlewares/metrics.middleware.ts) - Metrics collection
|
|
- [Error Handling](./error-handling-patterns.md) - Error middleware patterns
|