# 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 { 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>> GetFile( Guid fileId, CancellationToken ct = default) { var result = await _mediator.Send(new GetFileQuery(fileId), ct); return result == null ? NotFound(new ApiResponse { Success = false, Error = "File not found" }) : Ok(new ApiResponse { 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>> 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 { 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 { 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 /// Get file by ID. ``` ### ✅ Bilingual Documentation ```csharp // GOOD: EN/VI bilingual /// /// EN: Get file by ID. /// VI: Lấy thông tin file theo ID. /// ``` ## 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)