5.0 KiB
5.0 KiB
trigger
| 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
- Consistency: All APIs follow the same patterns
- Predictability: Developers can guess endpoint behavior
- Simplicity: Easy to understand and use
- Documentation: Self-documenting through OpenAPI
- 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
// 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
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
@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
-
Using Verbs in URLs: Non-RESTful endpoints
# BAD: POST /api/v1/createUser # GOOD: POST /api/v1/users -
Inconsistent Response Format: Different structures for different endpoints
// BAD: res.json({ user: data }) vs res.json({ result: data }) // GOOD: res.json({ success: true, data }) -
Wrong HTTP Status Codes: Using 200 for errors
// BAD: res.status(200).json({ error: 'Not found' }); // GOOD: res.status(404).json({ success: false, error: { code: 'NOT_FOUND' } }); -
Missing Pagination: Returning all records
// 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:
// 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 Found409- Conflict (duplicate)422- Unprocessable (business rule)429- Rate limited
Resources
- OpenAPI Specification - Official OpenAPI docs
- REST API Design - REST best practices
- Detailed Code Examples
- API Versioning Strategy - Versioning patterns
- API Gateway Advanced - Gateway patterns
- Middleware Patterns - Request handling