- Renamed auth-service to iam-service across various files for consistency. - Updated Dockerfiles, deployment configurations, and documentation to reflect the service name change. - Enhanced testing commands in documentation to point to the new iam-service. - Removed outdated auth-service files and configurations to streamline the project structure. - Improved bilingual documentation for clarity on the new service structure and usage.
15 KiB
RESTful API Design / Thiết Kế API RESTful
EN: RESTful API design standards for GoodGo microservices. Use when creating new API endpoints, designing DTOs, implementing controllers, writing OpenAPI documentation, or standardizing API responses. VI: Tiêu chuẩn thiết kế API RESTful cho các microservices của GoodGo. Sử dụng khi tạo endpoint API mới, thiết kế DTOs, triển khai controllers, viết tài liệu OpenAPI, hoặc chuẩn hóa response API.
Overview / Tổng Quan
EN: This skill covers the RESTful API design patterns and standards used across all GoodGo microservices. It ensures consistency, predictability, and maintainability of APIs through standardized URL structures, HTTP methods, response formats, error handling, and DTO validation.
VI: Skill này bao gồm các pattern và tiêu chuẩn thiết kế API RESTful được sử dụng trong tất cả các microservices của GoodGo. Nó đảm bảo tính nhất quán, dự đoán được và dễ bảo trì của APIs thông qua cấu trúc URL chuẩn hóa, HTTP methods, định dạng response, xử lý lỗi và validation DTO.
When to Use / Khi Nào Sử Dụng
EN: Use this skill when:
- Creating new API endpoints
- Designing request/response DTOs
- Implementing controllers and routes
- Writing OpenAPI/Swagger documentation
- Standardizing error responses
- Implementing pagination, filtering, and sorting
- Setting up API versioning
- Designing resource relationships
VI: Sử dụng skill này khi:
- Tạo endpoint API mới
- Thiết kế DTOs cho request/response
- Triển khai controllers và routes
- Viết tài liệu OpenAPI/Swagger
- Chuẩn hóa error responses
- Triển khai pagination, filtering và sorting
- Thiết lập API versioning
- Thiết kế quan hệ giữa các resources
Key Concepts / Khái Niệm Chính
1. URL Structure / Cấu Trúc URL
EN: URLs follow a hierarchical resource-based structure with versioning.
VI: URLs tuân theo cấu trúc phân cấp dựa trên resource với versioning.
https://api.goodgo.com/v1/{resource}/{id}/{sub-resource}
Examples:
GET /v1/users # List users
POST /v1/users # Create user
GET /v1/users/123 # Get user by ID
PUT /v1/users/123 # Update user
DELETE /v1/users/123 # Delete user
GET /v1/users/123/orders # Get user's orders
POST /v1/users/123/orders # Create order for user
2. HTTP Methods / Phương Thức HTTP
- GET: Retrieve resource(s) - Safe, Idempotent
- POST: Create new resource - Not idempotent
- PUT: Full update - Idempotent
- PATCH: Partial update - Idempotent
- DELETE: Remove resource - Idempotent
3. Standard Response Format / Định Dạng Response Chuẩn
All API responses follow a consistent structure with success, data, and optional metadata fields.
Tất cả API responses tuân theo cấu trúc nhất quán với các trường success, data, và metadata tùy chọn.
Common Patterns / Các Pattern Thường Dùng
Success Response Pattern
interface SuccessResponse<T> {
success: true;
data: T;
message?: string;
timestamp?: string;
pagination?: {
total: number;
skip: number;
take: number;
};
}
Example from codebase / Ví dụ từ codebase:
// services/iam-service/src/modules/identity/user/user.controller.ts
res.json({
success: true,
data: {
users: result.users,
pagination: {
total: result.total,
skip: filters.skip,
take: filters.take,
},
},
});
Error Response Pattern
interface ErrorResponse {
success: false;
error: {
code: string;
message: string;
details?: any;
field?: string;
};
timestamp?: string;
}
Example from codebase / Ví dụ từ codebase:
// services/iam-service/src/modules/identity/user/user.controller.ts
if (error instanceof z.ZodError) {
res.status(400).json({
success: false,
error: {
code: 'VALIDATION_ERROR',
message: 'Invalid filters',
details: error.errors,
},
});
return;
}
HTTP Status Codes / Mã Trạng Thái HTTP
// Success codes
200 OK // GET, PUT, PATCH success
201 Created // POST success with resource creation
204 No Content // DELETE success
// Client errors
400 Bad Request // Invalid request data
401 Unauthorized // Missing/invalid authentication
403 Forbidden // Valid auth but no permission
404 Not Found // Resource doesn't exist
409 Conflict // Resource conflict (duplicate)
422 Unprocessable // Validation errors
// Server errors
500 Internal Error // Unexpected server error
502 Bad Gateway // External service error
503 Service Unavailable // Service temporarily down
DTOs with Zod Validation / DTOs với Zod Validation
EN: DTOs use Zod for runtime validation with bilingual error messages.
VI: DTOs sử dụng Zod cho validation runtime với thông báo lỗi song ngữ.
Example from codebase / Ví dụ từ codebase:
// services/iam-service/src/modules/identity/identity.dto.ts
import { z } from 'zod';
export const CreateOrganizationDto = z.object({
name: z.string().min(1, 'Organization name is required / Tên tổ chức là bắt buộc').max(255),
domain: z.string().email().optional().or(z.string().min(1).max(255).optional()),
parentId: z.string().optional(),
settings: z.record(z.any()).optional(),
});
export type CreateOrganizationDto = z.infer<typeof CreateOrganizationDto>;
export const UserFiltersDto = z.object({
organizationId: z.string().optional(),
isActive: z.boolean().optional(),
emailVerified: z.boolean().optional(),
search: z.string().optional(),
skip: z.number().int().min(0).default(0),
take: z.number().int().min(1).max(100).default(20),
});
Controller Implementation Pattern / Pattern Triển Khai Controller
Example from codebase / Ví dụ từ codebase:
// services/iam-service/src/modules/identity/user/user.controller.ts
export class UserManagementController {
/**
* EN: List users
* VI: Liệt kê users
*/
async list(req: Request, res: Response): Promise<void> {
try {
const filters = UserFiltersDto.parse({
organizationId: req.query.organizationId as string,
isActive: req.query.isActive === 'true' ? true : req.query.isActive === 'false' ? false : undefined,
emailVerified: req.query.emailVerified === 'true' ? true : req.query.emailVerified === 'false' ? false : undefined,
search: req.query.search as string,
skip: parseInt(req.query.skip as string) || 0,
take: parseInt(req.query.take as string) || 20,
});
const result = await userManagementService.searchUsers(filters);
res.json({
success: true,
data: {
users: result.users,
pagination: {
total: result.total,
skip: filters.skip,
take: filters.take,
},
},
});
} catch (error: any) {
if (error instanceof z.ZodError) {
res.status(400).json({
success: false,
error: {
code: 'VALIDATION_ERROR',
message: 'Invalid filters',
details: error.errors,
},
});
return;
}
res.status(500).json({
success: false,
error: {
code: 'LIST_USERS_FAILED',
message: error.message || 'Failed to list users',
},
});
}
}
/**
* EN: Get user by ID
* VI: Lấy user theo ID
*/
async get(req: Request, res: Response): Promise<void> {
try {
const { id } = req.params;
const user = await userManagementService.getUser(id);
res.json({
success: true,
data: user,
});
} catch (error: any) {
if (error instanceof NotFoundError) {
res.status(404).json(error.toApiResponse());
return;
}
res.status(500).json({
success: false,
error: {
code: 'GET_USER_FAILED',
message: error.message || 'Failed to get user',
},
});
}
}
}
Error Handling with Custom Error Classes / Xử Lý Lỗi với Custom Error Classes
Example from codebase / Ví dụ từ codebase:
// services/iam-service/src/errors/http-error.ts
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.name = this.constructor.name;
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(),
};
}
}
export class NotFoundError extends HttpError {
constructor(resource: string = 'Resource / Tài nguyên', details?: any) {
super(`${resource} not found / ${resource} không tìm thấy`, 404, 'NOT_FOUND', true, details);
}
}
export class ValidationError extends HttpError {
constructor(message: string = 'Validation failed / Validation thất bại', details?: any) {
super(message, 422, 'VALIDATION_ERROR', true, details);
}
}
Best Practices / Thực Hành Tốt Nhất
1. Resource Naming / Đặt Tên Resource
- ✅ Use plural nouns (
/usersnot/user) - ✅ Use kebab-case for multi-word resources (
/user-profiles) - ✅ Keep URLs as short as possible
- ❌ Avoid verbs in URLs (use HTTP methods instead)
2. Versioning / Phiên Bản Hóa
- ✅ Include version in URL (
/v1/users) - ✅ Maintain backward compatibility
- ✅ Deprecate old versions gracefully with warnings
3. Security / Bảo Mật
- ✅ Always use HTTPS
- ✅ Implement rate limiting
- ✅ Validate all inputs with DTOs
- ✅ Use proper authentication/authorization middleware
- ✅ Never expose sensitive data in responses
4. Performance / Hiệu Năng
- ✅ Implement pagination for lists (use
skipandtake) - ✅ Use field filtering when possible (
selectin Prisma) - ✅ Cache responses appropriately
- ✅ Compress responses (gzip)
5. Documentation / Tài Liệu
- ✅ Keep OpenAPI spec up to date
- ✅ Include examples in documentation
- ✅ Document error responses
- ✅ Version your documentation
6. Error Handling / Xử Lý Lỗi
- ✅ Use consistent error response format
- ✅ Provide actionable error messages
- ✅ Include error codes for programmatic handling
- ✅ Log errors server-side, don't expose stack traces in production
Examples from Project / Ví Dụ Từ Dự Án
Controller Examples / Ví Dụ Controller
- User Management:
services/iam-service/src/modules/identity/user/user.controller.ts - Feature Controller:
services/iam-service/src/modules/feature/feature.controller.ts - RBAC Controller:
services/iam-service/src/modules/rbac/rbac.controller.ts
DTO Examples / Ví Dụ DTO
- Identity DTOs:
services/iam-service/src/modules/identity/identity.dto.ts - Auth DTOs:
services/iam-service/src/modules/auth/auth.dto.ts - RBAC DTOs:
services/iam-service/src/modules/rbac/rbac.dto.ts
Error Handling Examples / Ví Dụ Xử Lý Lỗi
- HTTP Error Classes:
services/iam-service/src/errors/http-error.ts - Error Middleware:
services/iam-service/src/middlewares/error.middleware.ts
Quick Reference / Tham Khảo Nhanh
Response Format Cheat Sheet / Bảng Tra Cứu Định Dạng Response
| Scenario | Status Code | Response Structure |
|---|---|---|
| Success (GET) | 200 | { success: true, data: {...} } |
| Success (POST) | 201 | { success: true, data: {...} } |
| Success (DELETE) | 200 | { success: true, message: "..." } |
| Validation Error | 400/422 | { success: false, error: { code, message, details } } |
| Not Found | 404 | { success: false, error: { code: "NOT_FOUND", message } } |
| Unauthorized | 401 | { success: false, error: { code: "UNAUTHORIZED", message } } |
| Forbidden | 403 | { success: false, error: { code: "FORBIDDEN", message } } |
| Server Error | 500 | { success: false, error: { code: "INTERNAL_ERROR", message } } |
Common DTO Patterns / Pattern DTO Thường Dùng
// Create DTO
const CreateDto = z.object({
requiredField: z.string().min(1),
optionalField: z.string().optional(),
});
// Update DTO (all fields optional)
const UpdateDto = z.object({
field1: z.string().optional(),
field2: z.number().optional(),
});
// Query/Filter DTO
const QueryDto = z.object({
page: z.number().int().min(1).default(1),
limit: z.number().int().min(1).max(100).default(20),
search: z.string().optional(),
sortBy: z.string().optional(),
order: z.enum(['asc', 'desc']).default('desc'),
});
Related Skills / Skills Liên Quan
- Database Prisma: For database operations and repository patterns
- Security: For authentication, authorization, and security best practices
- Testing Patterns: For testing API endpoints
- Documentation: For writing API documentation