Files
pos-system/docs/en/skills/api-design.md
Ho Ngoc Hai 6996e12ff0 docs: Add comprehensive Agent Skills documentation in English and Vietnamese
- Introduced new documentation for Agent Skills, detailing best practices, code patterns, common pitfalls, and quick references across various categories such as Architecture, Data Access, Security, Error Handling, Testing, Infrastructure, Communication, and Documentation.
- The documentation is structured to facilitate easy navigation and understanding, supporting developers in implementing consistent patterns on the GoodGo Platform.
- Both English and Vietnamese versions are provided to ensure accessibility for a wider audience.
2026-01-14 12:05:26 +07:00

5.8 KiB

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:

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:

{ "success": true, "data": {...}, "pagination": {...} }

Error response:

{ "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

[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

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

3. Implement Pagination

[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

// BAD: Returning raw data
return Ok(result);

Use Response Wrapper

// GOOD: Using ApiResponse wrapper
return Ok(new ApiResponse<FileDto> { Success = true, Data = result });

Missing API Versioning

// BAD: No versioning
[Route("api/files")]

Include Version

// GOOD: With API versioning
[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/files")]

Single Language Comments

// BAD: English only
/// <summary>Get file by ID.</summary>

Bilingual Documentation

// GOOD: EN/VI bilingual
/// <summary>
/// EN: Get file by ID.
/// VI: Lấy thông tin file theo ID.
/// </summary>

Additional Resources


Vietnamese Version: Tiêu Chuẩn Thiết Kế RESTful API