Files
pos-system/.agent/rules/api-design.md

172 lines
5.0 KiB
Markdown

---
trigger: always_on
---
# RESTful API Design Standards
## When to Use This Skill
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
## Core Principles
1. **Consistency**: All APIs follow the same patterns
2. **Predictability**: Developers can guess endpoint behavior
3. **Simplicity**: Easy to understand and use
4. **Documentation**: Self-documenting through OpenAPI
5. **Error Handling**: Clear, actionable error messages
## URL Structure
```
https://api.goodgo.com/v1/{resource}/{id}/{sub-resource}
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
```
## HTTP Methods
- **GET**: Retrieve resource(s) - Safe, Idempotent
- **POST**: Create new resource - Not idempotent
- **PUT**: Full update - Idempotent
- **PATCH**: Partial update - Idempotent
- **DELETE**: Remove resource - Idempotent
## Standard Response Format
```typescript
// Success
interface SuccessResponse<T> {
success: true;
data: T;
pagination?: { page: number; limit: number; total: number; totalPages: number };
}
// Error
interface ErrorResponse {
success: false;
error: { code: string; message: string; details?: any; field?: string };
}
```
## Key Patterns
### Request DTO
```typescript
export class CreateUserDto {
@IsEmail() @IsNotEmpty() email: string;
@MinLength(6) @IsNotEmpty() password: string;
@IsOptional() name?: string;
}
export class QueryUsersDto {
@IsOptional() @Min(1) page?: number = 1;
@IsOptional() @Min(1) @Max(100) limit?: number = 10;
@IsOptional() search?: string;
@IsOptional() @IsIn(['createdAt', 'name']) sortBy?: string = 'createdAt';
@IsOptional() @IsIn(['asc', 'desc']) order?: 'asc' | 'desc' = 'desc';
}
```
### Controller
```typescript
@Get()
async list(@Query() query: QueryUsersDto) {
const { data, total } = await this.userService.findAll(query);
return {
success: true,
data: data.map(UserResponseDto.fromEntity),
pagination: { page: query.page, limit: query.limit, total, totalPages: Math.ceil(total / query.limit) }
};
}
@Get(':id')
async getById(@Param('id') id: string) {
const user = await this.userService.findById(id);
if (!user) throw new NotFoundException({ success: false, error: { code: 'NOT_FOUND', message: 'User not found' } });
return { success: true, data: UserResponseDto.fromEntity(user) };
}
```
## Best Practices
- **Resource Naming**: Use plural nouns (`/users`), kebab-case for multi-word
- **Versioning**: Include version in URL (`/v1/users`), maintain backward compatibility
- **Security**: Use HTTPS, implement rate limiting, validate all inputs
- **Performance**: Implement pagination, use field filtering, cache responses
- **Documentation**: Keep OpenAPI spec up to date, include examples
## Common Mistakes
1. **Using Verbs in URLs**: Non-RESTful endpoints
```
# BAD: POST /api/v1/createUser
# GOOD: POST /api/v1/users
```
2. **Inconsistent Response Format**: Different structures for different endpoints
```typescript
// BAD: res.json({ user: data }) vs res.json({ result: data })
// GOOD: res.json({ success: true, data })
```
3. **Wrong HTTP Status Codes**: Using 200 for errors
```typescript
// BAD: res.status(200).json({ error: 'Not found' });
// GOOD: res.status(404).json({ success: false, error: { code: 'NOT_FOUND' } });
```
4. **Missing Pagination**: Returning all records
```typescript
// BAD: prisma.user.findMany()
// GOOD: prisma.user.findMany({ skip: (page - 1) * limit, take: limit })
```
## Quick Reference
| HTTP Method | Action | Idempotent | Status Codes |
|-------------|--------|------------|--------------|
| **GET** | Retrieve | Yes | 200, 404 |
| **POST** | Create | No | 201, 400, 409 |
| **PUT** | Full update | Yes | 200, 400, 404 |
| **PATCH** | Partial update | Yes | 200, 400, 404 |
| **DELETE** | Remove | Yes | 204, 404 |
**Response Format:**
```typescript
// Success: { success: true, data: T, pagination?: {...} }
// Error: { success: false, error: { code: string, message: string } }
```
**Common Error Codes:**
- `400` - Bad Request (validation)
- `401` - Unauthorized (no token)
- `403` - Forbidden (no permission)
- `404` - Not Found
- `409` - Conflict (duplicate)
- `422` - Unprocessable (business rule)
- `429` - Rate limited
## Resources
- [OpenAPI Specification](https://spec.openapis.org/oas/latest.html) - Official OpenAPI docs
- [REST API Design](https://restfulapi.net/) - REST best practices
- [Detailed Code Examples](./references/REFERENCE.md)
- [API Versioning Strategy](../api-versioning-strategy/SKILL.md) - Versioning patterns
- [API Gateway Advanced](../api-gateway-advanced/SKILL.md) - Gateway patterns
- [Middleware Patterns](../middleware-patterns/SKILL.md) - Request handling