# RESTful API Design Standards

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

## Overview

This skill provides standards for designing consistent, maintainable RESTful APIs across GoodGo microservices. It covers MediatR integration, response wrappers, OpenAPI documentation, and versioning strategies.

## When to Use

Apply this skill when:
- Creating new API endpoints
- Designing request/response DTOs
- Implementing controllers with MediatR
- Writing OpenAPI/Swagger documentation
- Standardizing error responses
- Implementing pagination and filtering

## Key Concepts

### Clean Architecture Layers

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

### Standard API Response

All endpoints use a consistent response wrapper:

```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" }
```

### URL Structure

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

GET    /api/v1/files              # List files
POST   /api/v1/files              # Create file
GET    /api/v1/files/{id}         # Get file by ID
PUT    /api/v1/files/{id}         # Update file
DELETE /api/v1/files/{id}         # Delete file
GET    /api/v1/files/{id}/versions # Get file versions
```

## Quick Start

### 1. Create Controller with 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. Use Record DTOs

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

### 3. Implement 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 | Action | Success | Error Codes |
|--------|--------|---------|-------------|
| **GET** | Retrieve | 200 | 404 |
| **POST** | Create | 200/201 | 400, 409 |
| **PUT** | Full update | 200 | 400, 404 |
| **PATCH** | Partial update | 200 | 400, 404 |
| **DELETE** | Remove | 200/204 | 404 |

## Common Error Codes

| Code | Meaning | When to Use |
|------|---------|-------------|
| 400 | Bad Request | Validation errors |
| 401 | Unauthorized | Missing/invalid token |
| 403 | Forbidden | No permission |
| 404 | Not Found | Resource doesn't exist |
| 409 | Conflict | Duplicate resource |
| 422 | Unprocessable | Business rule violation |
| 429 | Too Many Requests | Rate limited |

## Common Mistakes to Avoid

### ❌ Inconsistent Response Format
```csharp
// BAD: Returning raw data
return Ok(result);
```

### ✅ Use Response Wrapper
```csharp
// GOOD: Using ApiResponse wrapper
return Ok(new ApiResponse<FileDto> { Success = true, Data = result });
```

### ❌ Missing API Versioning
```csharp
// BAD: No versioning
[Route("api/files")]
```

### ✅ Include Version
```csharp
// GOOD: With API versioning
[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/files")]
```

### ❌ Single Language Comments
```csharp
// BAD: English only
/// <summary>Get file by ID.</summary>
```

### ✅ Bilingual Documentation
```csharp
// GOOD: EN/VI bilingual
/// <summary>
/// EN: Get file by ID.
/// VI: Lấy thông tin file theo ID.
/// </summary>
```

## Related Skills

- [CQRS & MediatR](./cqrs-mediatr.md) - Command/Query patterns
- [Error Handling](./error-handling-patterns.md) - Exception handling
- [Testing Patterns](./testing-patterns.md) - API testing
- [Security](./security.md) - Authentication & authorization

## Additional Resources

- **Full Skill Reference**: [`.agent/skills/api-design/SKILL.md`](../../.agent/skills/api-design/SKILL.md)
- **Code Examples**: [`.agent/skills/api-design/references/REFERENCE.md`](../../.agent/skills/api-design/references/REFERENCE.md)
- **Project Rules**: [Project Standards](./project-rules.md)

---

**Vietnamese Version**: [Tiêu Chuẩn Thiết Kế RESTful API](../../vi/skills/api-design.md)
