# Chiến Lược Versioning API (API Versioning Strategy)

API versioning strategies for GoodGo microservices including semantic versioning, backward compatibility patterns, API deprecation, version negotiation, and breaking changes handling.
> Các chiến lược versioning API cho GoodGo microservices bao gồm semantic versioning, backward compatibility patterns, API deprecation, version negotiation, và xử lý breaking changes.

## Tổng Quan

API versioning strategies enable managing API evolution while maintaining compatibility and clearly communicating changes to consumers.

Các chiến lược versioning API cho phép quản lý sự phát triển API đồng thời duy trì tương thích và giao tiếp rõ ràng các thay đổi tới consumers.

## Khi Nào Sử Dụng

Use this skill when versioning APIs, handling breaking changes, or implementing deprecation.

Sử dụng skill này khi:
- Versioning APIs
- Xử lý breaking changes
- Implement API deprecation
- Duy trì backward compatibility
- Implement version negotiation
- Quản lý nhiều API versions
- Lập kế hoạch phát triển API
- Giao tiếp các thay đổi API với consumers

## Các Khái Niệm Cốt Lõi

### Các Chiến Lược Versioning

1. **URL Path Versioning**: `/api/v1/users`, `/api/v2/users`
2. **Header Versioning**: `Accept: application/vnd.goodgo.v1+json`
3. **Query Parameter**: `/api/users?version=1`
4. **Semantic Versioning**: Major.Minor.Patch (ví dụ: 1.2.3)

### Các Loại Tương Thích

- **Backward Compatible**: Version mới hoạt động với clients cũ
- **Forward Compatible**: Version cũ hoạt động với clients mới
- **Breaking Changes**: Thay đổi không tương thích yêu cầu version mới

## Version Negotiation

Version negotiation allows clients to request a specific API version through headers while maintaining clean URLs. The middleware extracts the version from the `Accept` header and routes to the appropriate handler.

Version negotiation cho phép clients yêu cầu một API version cụ thể thông qua headers trong khi duy trì URLs sạch. Middleware trích xuất version từ header `Accept` và định tuyến tới handler phù hợp.

```mermaid
sequenceDiagram
    participant Client
    participant Middleware as Version Negotiation<br/>Middleware
    participant Controller as Version-Aware<br/>Controller
    participant Service

    Client->>Middleware: Request with Accept header<br/>Accept: application/vnd.goodgo.v1+json
    Middleware->>Middleware: Extract version from header
    alt Version specified
        Middleware->>Middleware: Parse version number
        alt Version supported
            Middleware->>Controller: Set req.apiVersion = 1
            Controller->>Controller: Check version
            Controller->>Service: Call service method
            Service-->>Controller: Return data
            Controller->>Controller: Format response for v1
            Controller-->>Client: v1 response format
        else Version not supported
            Middleware-->>Client: 400 Unsupported Version
        end
    else No version specified
        Middleware->>Controller: Set req.apiVersion = latest (2)
        Controller->>Service: Call service method
        Service-->>Controller: Return data
        Controller->>Controller: Format response for v2
        Controller-->>Client: v2 response format (default)
    end
```

### Implementation

```typescript
// src/middlewares/version-negotiation.middleware.ts
// EN: Version negotiation middleware
// VI: Middleware version negotiation
import { Request, Response, NextFunction } from 'express';
import { logger } from '@goodgo/logger';

export function versionNegotiation(
  req: Request,
  res: Response,
  next: NextFunction
): void {
  // EN: Extract version from Accept header
  // VI: Trích xuất version từ Accept header
  const acceptHeader = req.headers.accept || '';
  const versionMatch = acceptHeader.match(/application\/vnd\.goodgo\.v(\d+)\+json/);

  if (versionMatch) {
    const requestedVersion = parseInt(versionMatch[1], 10);
    req.apiVersion = requestedVersion;

    // EN: Check if version is supported
    // VI: Kiểm tra xem version có được hỗ trợ không
    const supportedVersions = [1, 2];
    if (!supportedVersions.includes(requestedVersion)) {
      return res.status(400).json({
        success: false,
        error: {
          code: 'UNSUPPORTED_VERSION',
          message: `API version ${requestedVersion} is not supported. Supported versions: ${supportedVersions.join(', ')}`,
        },
      });
    }
  } else {
    // EN: Default to latest version
    // VI: Mặc định version mới nhất
    req.apiVersion = 2;
  }

  next();
}
```

## API Deprecation Timeline

API deprecation follows a structured timeline to give consumers adequate time to migrate. The lifecycle progresses through active, deprecated, sunset, and removed phases.

API deprecation tuân theo một timeline có cấu trúc để cung cấp cho consumers đủ thời gian để migrate. Vòng đời tiến triển qua các giai đoạn active, deprecated, sunset, và removed.

```mermaid
gantt
    title API Version Lifecycle Timeline
    dateFormat YYYY-MM-DD
    section Version 1
    Active (v1 only)           :active, v1-active, 2024-01-01, 2024-06-01
    Deprecated (v1 + v2)       :crit, v1-deprecated, 2024-06-01, 2024-12-31
    Sunset Period              :v1-sunset, 2024-12-31, 2025-01-31
    Removed                    :v1-removed, 2025-01-31, 1d
    section Version 2
    Development                :v2-dev, 2024-03-01, 2024-06-01
    Active (v1 + v2)           :active, v2-active, 2024-06-01, 2025-12-31
```

### Deprecation Phases

```mermaid
stateDiagram-v2
    [*] --> Active: Version Released
    Active --> Deprecated: New Version Released<br/>Add Deprecation Headers
    Deprecated --> Sunset: Sunset Date Reached<br/>Stop Accepting New Requests
    Sunset --> Removed: Grace Period Ended<br/>Remove Routes
    Removed --> [*]
    
    note right of Active
        - Version fully supported
        - No warnings
        - All features available
    end note
    
    note right of Deprecated
        - Deprecation header set
        - Warning headers added
        - Migration guide provided
        - Still functional
    end note
    
    note right of Sunset
        - Read-only mode
        - No new requests accepted
        - Existing requests honored
    end note
```

### Deprecation Headers

```typescript
// src/middlewares/deprecation.middleware.ts
// EN: Deprecation warning middleware
// VI: Middleware cảnh báo deprecation
export function deprecationMiddleware(version: string, sunsetDate: string) {
  return (req: Request, res: Response, next: NextFunction): void => {
    if (req.apiVersion && parseInt(req.apiVersion.toString()) < parseInt(version)) {
      res.setHeader('Deprecation', 'true');
      res.setHeader('Sunset', sunsetDate);
      res.setHeader('Link', `<${req.url.replace(/\/v\d+/, `/v${version}`)}>; rel="successor-version"`);
      res.setHeader('Warning', `299 - "API version ${req.apiVersion} is deprecated. Please migrate to version ${version} by ${sunsetDate}"`);
    }

    next();
  };
}

// Usage
router.use('/v1', deprecationMiddleware('2', '2024-12-31'), v1Router);
```

## Migration Flow

Breaking changes require a careful 3-phase migration strategy to ensure zero downtime and smooth client transitions.

Breaking changes yêu cầu một chiến lược migration 3 giai đoạn cẩn thận để đảm bảo zero downtime và chuyển đổi client mượt mà.

```mermaid
flowchart TD
    Start([Breaking Change Identified]) --> Phase1[Phase 1: Support Both Versions]
    
    Phase1 --> DeployV2[Deploy v2 alongside v1]
    DeployV2 --> Monitor1[Monitor v1 and v2 usage]
    Monitor1 --> Wait1[Wait for client adoption]
    Wait1 --> Phase2{Sufficient<br/>v2 adoption?}
    
    Phase2 -->|No| Wait1
    Phase2 -->|Yes| Phase2Start[Phase 2: Deprecate v1]
    
    Phase2Start --> AddHeaders[Add deprecation headers to v1]
    AddHeaders --> NotifyClients[Notify clients via<br/>deprecation warnings]
    NotifyClients --> ProvideGuide[Provide migration guide]
    ProvideGuide --> Monitor2[Monitor migration progress]
    Monitor2 --> Wait2[Wait until sunset date]
    Wait2 --> Phase3{Sunset date<br/>reached?}
    
    Phase3 -->|No| Monitor2
    Phase3 -->|Yes| Phase3Start[Phase 3: Remove v1]
    
    Phase3Start --> StopAccepting[Stop accepting new v1 requests]
    StopAccepting --> GracePeriod[Grace period for<br/>existing requests]
    GracePeriod --> RemoveRoutes[Remove v1 routes]
    RemoveRoutes --> End([Migration Complete])
    
    style Phase1 fill:#e1f5ff
    style Phase2Start fill:#fff4e1
    style Phase3Start fill:#ffe1e1
    style End fill:#e1ffe1
```

### Implementation Strategy

```typescript
// src/core/api/migration.strategy.ts
// EN: Migration strategy for breaking changes
// VI: Chiến lược migration cho breaking changes
export class MigrationStrategy {
  /**
   * EN: Phase 1: Support both versions
   * VI: Giai đoạn 1: Hỗ trợ cả hai versions
   */
  phase1SupportBoth(): void {
    // EN: Keep v1, add v2
    // VI: Giữ v1, thêm v2
    router.use('/v1', v1Router);
    router.use('/v2', v2Router);
  }

  /**
   * EN: Phase 2: Deprecate v1
   * VI: Giai đoạn 2: Deprecate v1
   */
  phase2DeprecateV1(): void {
    router.use('/v1', deprecationMiddleware('2', '2024-12-31'), v1Router);
    router.use('/v2', v2Router);
  }

  /**
   * EN: Phase 3: Remove v1
   * VI: Giai đoạn 3: Xóa v1
   */
  phase3RemoveV1(): void {
    // EN: After sunset date, remove v1 routes
    // VI: Sau sunset date, xóa v1 routes
    router.use('/v2', v2Router);
  }
}
```

## URL Path Versioning

### Implementation

```typescript
// src/routes/index.ts
// EN: Route versioning
// VI: Route versioning
import { Router } from 'express';
import v1Router from './v1';
import v2Router from './v2';

const router = Router();

// EN: Version 1 routes
// VI: Routes version 1
router.use('/v1', v1Router);

// EN: Version 2 routes
// VI: Routes version 2
router.use('/v2', v2Router);

export default router;
```

## Semantic Versioning

### Version Structure

```
MAJOR.MINOR.PATCH

MAJOR: Breaking changes
MINOR: Backward-compatible additions
PATCH: Backward-compatible bug fixes
```

### Version Response

```typescript
// src/core/api/version.middleware.ts
// EN: Add version to response
// VI: Thêm version vào response
export function versionMiddleware(req: Request, res: Response, next: NextFunction): void {
  const originalJson = res.json.bind(res);

  res.json = (data: any) => {
    const response = {
      ...data,
      metadata: {
        ...data.metadata,
        apiVersion: req.apiVersion || '2.0.0',
        serviceVersion: process.env.SERVICE_VERSION || '1.0.0',
      },
    };

    return originalJson(response);
  };

  next();
}
```

## Backward Compatibility

### Compatibility Layer

```typescript
// src/core/api/compatibility.adapter.ts
// EN: Backward compatibility adapter
// VI: Adapter tương thích ngược
export class CompatibilityAdapter {
  /**
   * EN: Adapt v1 response to v2 format
   * VI: Adapt response v1 sang format v2
   */
  adaptV1ToV2(v1Data: any): any {
    return {
      success: true,
      data: {
        user: {
          ...v1Data,
          profile: null, // EN: Add default for new field / VI: Thêm mặc định cho field mới
        },
      },
      metadata: {
        version: '2.0.0',
        adapted: true,
      },
    };
  }

  /**
   * EN: Adapt v2 request to v1 format
   * VI: Adapt request v2 sang format v1
   */
  adaptV2RequestToV1(v2Request: any): any {
    return {
      email: v2Request.email,
      name: v2Request.name,
      // EN: Ignore new fields / VI: Bỏ qua các field mới
    };
  }
}
```

## Best Practices

1. **Versioning Strategy**: Choose URL path or header, be consistent / Chọn chiến lược và nhất quán
2. **Semantic Versioning**: Use MAJOR.MINOR.PATCH / Sử dụng semantic versioning
3. **Deprecation**: Always deprecate before removing / Luôn deprecate trước khi xóa
4. **Migration Guide**: Provide clear migration documentation / Cung cấp tài liệu migration rõ ràng
5. **Backward Compatibility**: Maintain compatibility when possible / Duy trì tương thích khi có thể
6. **Communication**: Clearly communicate version changes / Giao tiếp rõ ràng các thay đổi version

## Common Mistakes

1. **No Deprecation Period**: Breaking clients suddenly / Phá vỡ clients đột ngột
   ```typescript
   // ❌ BAD: Remove v1 immediately
   router.use('/v2', v2Router);

   // ✅ GOOD: Deprecate with sunset date
   router.use('/v1', deprecationMiddleware('2', '2024-12-31'), v1Router);
   router.use('/v2', v2Router);
   ```

2. **Breaking Changes Without Major Version**: Client confusion / Gây nhầm lẫn cho client
   ```
   # ❌ BAD: Breaking change in minor version
   v1.1.0 → Changed response format

   # ✅ GOOD: Breaking change = new major version
   v1.x.x → v2.0.0 (new response format)
   ```

3. **Inconsistent Versioning Strategy**: Mixed approaches / Chiến lược không nhất quán
   ```typescript
   // ❌ BAD: Mix URL and header versioning
   /api/v1/users + Accept: application/vnd.v2+json

   // ✅ GOOD: Choose one approach
   /api/v1/users OR Accept: application/vnd.goodgo.v1+json
   ```

## Quick Reference

| Strategy | Pros | Cons | Use When |
|----------|------|------|----------|
| **URL Path** | Clear, cacheable | URL changes | Public APIs |
| **Header** | Clean URLs | Less visible | Internal APIs |
| **Query Param** | Simple | Not RESTful | Quick prototypes |

**Semantic Versioning:**
```
MAJOR.MINOR.PATCH
  │     │     └── Bug fixes (backward compatible)
  │     └──────── New features (backward compatible)
  └────────────── Breaking changes
```

**Version Lifecycle:**
```
v1 Active → v2 Released → v1 Deprecated → v1 Sunset → v1 Removed
   │            │              │              │           │
   │            │         Add headers     Remove from   Delete
   │         Support       + warnings       docs       routes
  Solo        both
```

**Deprecation Headers:**
```http
Deprecation: true
Sunset: Sat, 31 Dec 2024 23:59:59 GMT
Warning: 299 - "API v1 is deprecated. Migrate to v2 by 2024-12-31"
Link: </api/v2/users>; rel="successor-version"
```

## Tài Nguyên

- [API Design](./api-design.md) - API design patterns
- [Middleware Patterns](./middleware-patterns.md) - Middleware patterns
- [Project Rules](./project-rules.md) - GoodGo standards
- Skill Source: `.cursor/skills/api-versioning-strategy/SKILL.md`
