# API Versioning Strategy

## INT-011: Add API versioning strategy

**Date**: 2025-12-25  
**Status**: Completed

## Overview

This document defines the comprehensive API versioning strategy for Veza Backend API. It provides guidelines for both API developers and consumers on how to handle API versions, breaking changes, and migrations.

**Current Version**: `v1`  
**Status**: Active  
**Implementation**: URL Path Versioning (primary), Header-based (supported)

## Versioning Methods

The Veza API supports multiple methods for specifying the API version, in order of precedence:

### 1. URL Path Versioning (Primary)

The version is included in the URL path:

```
GET /api/v1/tracks
POST /api/v1/playlists
GET /api/v2/users/me
```

**Advantages**:
- Clear and explicit
- Easy to understand
- RESTful
- Cache-friendly

**Format**: `/api/v{major}/...`

### 2. Header-Based Versioning (Supported)

Clients can specify the version using HTTP headers:

#### X-API-Version Header

```
X-API-Version: v1
```

#### Accept Header (Content Negotiation)

```
Accept: application/vnd.veza.v1+json
```

**Advantages**:
- Clean URLs
- Flexible for clients
- Supports content negotiation

**Note**: When using header-based versioning, the URL path should still include `/api/` but the version can be omitted or different.

## Version Format

- **Format**: `v{major}`
- **Examples**: `v1`, `v2`, `v3`
- **Major versions** indicate breaking changes
- **No minor/patch versions** in the API path (semantic versioning is used for the application itself)

## Version Lifecycle

### Current Version: v1

- **Status**: Active
- **Released**: 2025-01-01
- **Deprecation Date**: TBD
- **End of Life**: TBD
- **Breaking Changes**: None planned
- **Description**: Current stable API version

### Version States

1. **Active**: Current recommended version, fully supported
2. **Deprecated**: Still functional but will be removed in the future
3. **End of Life**: No longer supported, requests will fail

### Version Lifecycle Timeline

```
┌─────────────┐
│   Active    │ ← Current version, fully supported
└──────┬──────┘
       │
       │ (6+ months notice)
       ▼
┌─────────────┐
│ Deprecated  │ ← Still works, but marked for removal
└──────┬──────┘
       │
       │ (12+ months support)
       ▼
┌─────────────┐
│ End of Life │ ← Removed, requests fail
└─────────────┘
```

## Breaking vs Non-Breaking Changes

### Breaking Changes (Require New Major Version)

Breaking changes require a new major version (e.g., `v1` → `v2`):

#### Request Changes
- ✅ **Removed endpoints**
- ✅ **Changed HTTP methods** (GET → POST)
- ✅ **Removed required fields** in request body
- ✅ **Changed field types** (string → integer)
- ✅ **Changed field names** (camelCase → snake_case)
- ✅ **Changed validation rules** (making optional fields required)
- ✅ **Changed authentication mechanisms**

#### Response Changes
- ✅ **Changed response structure** (removing fields)
- ✅ **Changed field types** in responses
- ✅ **Changed error response format**
- ✅ **Removed response fields**
- ✅ **Changed HTTP status codes** for same endpoint

#### Examples of Breaking Changes

```json
// v1 Response
{
  "id": "123",
  "name": "Track Name"
}

// v2 Response (BREAKING - removed 'name', added 'title')
{
  "id": "123",
  "title": "Track Name"
}
```

### Non-Breaking Changes (Same Version)

These changes can be made within the same version:

#### Request Changes
- ✅ **New optional fields** in request body
- ✅ **New query parameters**
- ✅ **New endpoints**
- ✅ **Relaxed validation** (making required fields optional)

#### Response Changes
- ✅ **New optional fields** in responses
- ✅ **New endpoints**
- ✅ **New error codes** (additional error types)
- ✅ **Performance improvements**
- ✅ **Bug fixes** (fixing incorrect behavior)

#### Examples of Non-Breaking Changes

```json
// v1 Response
{
  "id": "123",
  "name": "Track Name"
}

// v1 Response (NON-BREAKING - added optional field)
{
  "id": "123",
  "name": "Track Name",
  "description": "Optional description"  // New field
}
```

## Creating a New API Version

### When to Create a New Version

Create a new major version when:
1. You need to make breaking changes
2. You want to introduce significant architectural changes
3. You need to deprecate old patterns
4. You want to clean up technical debt

### Process for Creating v2 (Example)

#### Step 1: Planning (3-6 months before release)

1. **Identify breaking changes**
   - List all breaking changes
   - Document impact on consumers
   - Create migration guide

2. **Design new version**
   - Design new endpoints
   - Design new request/response formats
   - Plan backward compatibility strategy

3. **Announce to consumers**
   - Send deprecation notice for v1
   - Announce v2 release date
   - Provide migration timeline

#### Step 2: Implementation

1. **Create v2 handlers**
   ```go
   // New v2 handler
   func (h *TrackHandler) GetTrackV2(c *gin.Context) {
       // v2 implementation
   }
   ```

2. **Register v2 version**
   ```go
   vm.RegisterVersion(&APIVersion{
       Version:     "v2",
       Deprecated:  false,
       Description: "New API version with improved endpoints",
   })
   ```

3. **Add v2 routes**
   ```go
   v2 := router.Group("/api/v2")
   v2.GET("/tracks/:id", trackHandler.GetTrackV2)
   ```

4. **Update tests**
   - Add tests for v2 endpoints
   - Test backward compatibility
   - Test migration scenarios

#### Step 3: Release

1. **Deploy v2**
   - Deploy to staging
   - Test thoroughly
   - Deploy to production

2. **Monitor usage**
   - Track v1 vs v2 usage
   - Monitor errors
   - Collect feedback

3. **Update documentation**
   - Update Swagger/OpenAPI docs
   - Update migration guides
   - Update examples

#### Step 4: Deprecation (6-12 months after v2 release)

1. **Mark v1 as deprecated**
   ```go
   vm.RegisterVersion(&APIVersion{
       Version:     "v1",
       Deprecated:  true,
       SunsetDate:  "2026-12-31T00:00:00Z",
       Description: "Deprecated - migrate to v2",
   })
   ```

2. **Add deprecation headers**
   - `X-API-Version-Deprecated: true`
   - `Sunset: 2026-12-31T00:00:00Z`

3. **Notify consumers**
   - Send deprecation notices
   - Provide migration timeline
   - Offer support for migration

#### Step 5: End of Life (12+ months after deprecation)

1. **Remove v1 support**
   - Remove v1 routes
   - Remove v1 handlers
   - Update documentation

2. **Final notification**
   - Send final notice
   - Provide last migration window
   - Close v1 support tickets

## Guidelines for API Developers

### When Adding New Features

1. **Check if it's breaking**
   - If breaking → new major version
   - If non-breaking → same version

2. **Document changes**
   - Update Swagger annotations
   - Update API documentation
   - Add migration notes if needed

3. **Maintain backward compatibility**
   - During deprecation period
   - Test both versions
   - Don't break existing consumers

### Code Organization

```
internal/
├── handlers/
│   ├── track_handler.go      # v1 handlers
│   └── track_handler_v2.go   # v2 handlers (when needed)
├── api/
│   ├── router.go             # Route setup
│   └── versioning.go         # Version management
```

### Testing Strategy

1. **Test both versions**
   ```go
   func TestTrackEndpoint_V1(t *testing.T) {
       // Test v1 endpoint
   }
   
   func TestTrackEndpoint_V2(t *testing.T) {
       // Test v2 endpoint
   }
   ```

2. **Test backward compatibility**
   - Ensure v1 still works
   - Test migration scenarios
   - Test deprecation warnings

## Guidelines for API Consumers

### Best Practices

1. **Always specify version explicitly**
   ```bash
   # Good
   GET /api/v1/tracks
   
   # Also good
   GET /api/tracks
   X-API-Version: v1
   ```

2. **Monitor deprecation notices**
   - Check `/api/versions` endpoint
   - Monitor response headers
   - Subscribe to API updates

3. **Test new versions early**
   - Test in staging
   - Migrate gradually
   - Don't wait until EOL

4. **Handle version errors gracefully**
   ```javascript
   if (response.status === 400 && response.body.error === "Unsupported API version") {
       // Handle version error
       console.log("Available versions:", response.body.available_versions);
   }
   ```

### Migration Checklist

When migrating from v1 to v2:

- [ ] Review breaking changes documentation
- [ ] Test v2 endpoints in staging
- [ ] Update API client code
- [ ] Update request/response handling
- [ ] Test all affected features
- [ ] Update error handling
- [ ] Deploy to production
- [ ] Monitor for issues
- [ ] Remove v1 code after successful migration

## Version Information Endpoint

### GET /api/versions

Returns information about all available API versions:

```json
{
  "current_version": "v1",
  "versions": {
    "v1": {
      "version": "v1",
      "deprecated": false,
      "description": "Current stable API version"
    },
    "v2": {
      "version": "v2",
      "deprecated": false,
      "description": "New API version",
      "sunset_date": null
    }
  }
}
```

## Response Headers

The API includes version information in response headers:

- `X-API-Version`: Current version being used
- `X-API-Version-Deprecated`: `true` if version is deprecated
- `Sunset`: RFC3339 date when version will be removed (if deprecated)

## Examples

### Using URL Path Versioning

```bash
# v1 endpoint
curl https://api.veza.app/api/v1/tracks

# v2 endpoint
curl https://api.veza.app/api/v2/tracks
```

### Using Header Versioning

```bash
# Using X-API-Version header
curl -H "X-API-Version: v1" https://api.veza.app/api/tracks

# Using Accept header
curl -H "Accept: application/vnd.veza.v1+json" https://api.veza.app/api/tracks
```

### Handling Deprecated Versions

```bash
# Response includes deprecation headers
curl -H "X-API-Version: v1" https://api.veza.app/api/tracks

# Response headers:
# X-API-Version: v1
# X-API-Version-Deprecated: true
# Sunset: 2026-12-31T00:00:00Z
```

## Decision Matrix

| Change Type | Action | Version Impact |
|------------|--------|----------------|
| New endpoint | Add to current version | Same version |
| New optional field | Add to current version | Same version |
| Remove endpoint | Create new version | New major version |
| Change field type | Create new version | New major version |
| Change field name | Create new version | New major version |
| Remove required field | Create new version | New major version |
| Add required field | Create new version | New major version |
| Change error format | Create new version | New major version |
| Performance improvement | Add to current version | Same version |
| Bug fix | Add to current version | Same version |

## Testing

### Running Version Tests

```bash
cd veza-backend-api
go test ./internal/api/... -v
```

### Test Coverage

- ✅ Version manager functionality
- ✅ Version middleware
- ✅ Header-based versioning
- ✅ URL path versioning
- ✅ Deprecated version handling
- ✅ Version info endpoint

## References

- [REST API Versioning Best Practices](https://restfulapi.net/versioning/)
- [API Versioning Strategies](https://www.baeldung.com/rest-versioning)
- [Semantic Versioning](https://semver.org/)
- [RFC 7231 - HTTP/1.1 Semantics](https://tools.ietf.org/html/rfc7231)

## Maintenance

This strategy should be reviewed and updated:
- When creating a new major version
- When deprecating a version
- When changing versioning approach
- Annually for best practices updates

---

**Last Updated**: 2025-12-25  
**Maintained By**: Veza Backend Team  
**Related Documents**: 
- `veza-backend-api/docs/API_VERSIONING.md` - Technical implementation details
- `OPENAPI_MAINTENANCE_GUIDE.md` - API documentation maintenance

