---
name: api-design
description: RESTful API design standards for GoodGo microservices. Use for new API endpoints, DTOs, controllers, OpenAPI documentation, or standardized responses.
compatibility: "express>=4.18, zod>=3, @types/express"
---

# 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
