# Tiêu Chuẩn Thiết Kế RESTful API

> **Skill**: `api-design`  
> **Compatibility**: .NET 10+, ASP.NET Core, MediatR, Swashbuckle, Asp.Versioning

## Tổng Quan

Skill này cung cấp tiêu chuẩn thiết kế RESTful APIs nhất quán, dễ bảo trì cho GoodGo microservices. Bao gồm tích hợp MediatR, response wrappers, OpenAPI documentation, và chiến lược versioning.

## Khi Nào Sử Dụng

Áp dụng skill này khi:
- Tạo API endpoints mới
- Thiết kế request/response DTOs
- Triển khai controllers với MediatR
- Viết tài liệu OpenAPI/Swagger
- Chuẩn hóa error responses
- Triển khai pagination và filtering

## Khái Niệm Cốt Lõi

### Các Tầng Clean Architecture

```
src/
├── ServiceName.API/           # Controllers, DTOs, Middleware
│   ├── Controllers/           # API Controllers
│   └── Application/           # Commands, Queries, Handlers
├── ServiceName.Domain/        # Entities, Aggregates, Interfaces
└── ServiceName.Infrastructure/ # Repositories, External Services
```

### Response API Chuẩn

Tất cả endpoints sử dụng response wrapper nhất quán:

```csharp
public class ApiResponse<T>
{
    public bool Success { get; set; }
    public T? Data { get; set; }
    public string? Error { get; set; }
    public PaginationInfo? Pagination { get; set; }
}
```

**Success response:**
```json
{ "success": true, "data": {...}, "pagination": {...} }
```

**Error response:**
```json
{ "success": false, "error": "Error message" }
```

### Cấu Trúc URL

```
/api/v{version}/{resource}/{id?}/{sub-resource?}

GET    /api/v1/files              # Liệt kê files
POST   /api/v1/files              # Tạo file
GET    /api/v1/files/{id}         # Lấy file theo ID
PUT    /api/v1/files/{id}         # Cập nhật file
DELETE /api/v1/files/{id}         # Xóa file
GET    /api/v1/files/{id}/versions # Lấy versions của file
```

## Bắt Đầu Nhanh

### 1. Tạo Controller với MediatR

```csharp
[ApiController]
[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/files")]
[SwaggerTag("File Management - Upload, download, and manage files")]
public class FilesController : ControllerBase
{
    private readonly IMediator _mediator;

    public FilesController(IMediator mediator) => _mediator = mediator;

    [HttpGet("{fileId:guid}")]
    [Authorize]
    [SwaggerOperation(Summary = "Get file by ID")]
    [SwaggerResponse(200, "File retrieved successfully")]
    [SwaggerResponse(404, "File not found")]
    public async Task<ActionResult<ApiResponse<FileDto>>> GetFile(
        Guid fileId,
        CancellationToken ct = default)
    {
        var result = await _mediator.Send(new GetFileQuery(fileId), ct);
        
        return result == null
            ? NotFound(new ApiResponse<FileDto> { Success = false, Error = "File not found" })
            : Ok(new ApiResponse<FileDto> { Success = true, Data = result });
    }
}
```

### 2. Sử Dụng Record DTOs

```csharp
public record FileDto(
    Guid Id,
    string UserId,
    string FileName,
    string ContentType,
    long FileSizeBytes,
    string AccessLevel,
    DateTime UploadedAt);
```

### 3. Triển Khai Pagination

```csharp
[HttpGet]
public async Task<ActionResult<ApiResponse<UserFilesResult>>> GetFiles(
    [FromQuery] int skip = 0,
    [FromQuery] int take = 20,
    CancellationToken ct = default)
{
    var result = await _mediator.Send(new GetUserFilesQuery(skip, take), ct);

    return Ok(new ApiResponse<UserFilesResult> 
    { 
        Success = true, 
        Data = result,
        Pagination = new PaginationInfo(
            Page: skip / take + 1,
            Limit: take,
            Total: result.TotalCount,
            TotalPages: (int)Math.Ceiling(result.TotalCount / (double)take))
    });
}
```

## HTTP Methods & Status Codes

| Method | Hành Động | Success | Error Codes |
|--------|-----------|---------|-------------|
| **GET** | Lấy dữ liệu | 200 | 404 |
| **POST** | Tạo mới | 200/201 | 400, 409 |
| **PUT** | Cập nhật toàn bộ | 200 | 400, 404 |
| **PATCH** | Cập nhật một phần | 200 | 400, 404 |
| **DELETE** | Xóa | 200/204 | 404 |

## Mã Lỗi Phổ Biến

| Code | Ý Nghĩa | Khi Nào Dùng |
|------|---------|--------------|
| 400 | Bad Request | Lỗi validation |
| 401 | Unauthorized | Thiếu/sai token |
| 403 | Forbidden | Không có quyền |
| 404 | Not Found | Resource không tồn tại |
| 409 | Conflict | Resource trùng lặp |
| 422 | Unprocessable | Vi phạm business rule |
| 429 | Too Many Requests | Bị rate limit |

## Lỗi Thường Gặp Cần Tránh

### ❌ Response Format Không Nhất Quán
```csharp
// SAI: Trả về raw data
return Ok(result);
```

### ✅ Dùng Response Wrapper
```csharp
// ĐÚNG: Dùng ApiResponse wrapper
return Ok(new ApiResponse<FileDto> { Success = true, Data = result });
```

### ❌ Thiếu API Versioning
```csharp
// SAI: Không có versioning
[Route("api/files")]
```

### ✅ Có Version
```csharp
// ĐÚNG: Với API versioning
[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/files")]
```

### ❌ Comment Một Ngôn Ngữ
```csharp
// SAI: Chỉ tiếng Anh
/// <summary>Get file by ID.</summary>
```

### ✅ Tài Liệu Song Ngữ
```csharp
// ĐÚNG: Song ngữ EN/VI
/// <summary>
/// EN: Get file by ID.
/// VI: Lấy thông tin file theo ID.
/// </summary>
```

## Skills Liên Quan

- [CQRS & MediatR](./cqrs-mediatr.md) - Mẫu Command/Query
- [Xử Lý Lỗi](./error-handling-patterns.md) - Exception handling
- [Mẫu Testing](./testing-patterns.md) - API testing
- [Bảo Mật](./security.md) - Authentication & authorization

## Tài Nguyên Bổ Sung

- **Tài Liệu Skill Đầy Đủ**: [`.agent/skills/api-design/SKILL.md`](../../.agent/skills/api-design/SKILL.md)
- **Ví Dụ Code**: [`.agent/skills/api-design/references/REFERENCE.md`](../../.agent/skills/api-design/references/REFERENCE.md)
- **Quy Tắc Dự Án**: [Tiêu Chuẩn Dự Án](./project-rules.md)

---

**English Version**: [RESTful API Design Standards](../../en/skills/api-design.md)
