- Added /api/v2/greet POST endpoint with JSON request/response - Implemented ServiceV2 with Hello my friend <name>! greeting format - Added api.v2_enabled feature flag (default: false) - Extended BDD tests to cover v2 scenarios - Maintained full backward compatibility with v1 API - Added DLC_API_V2_ENABLED environment variable support - Created ADR 0010-api-v2-feature-flag.md - Updated configuration system to support API versioning
163 lines
5.8 KiB
Markdown
163 lines
5.8 KiB
Markdown
# 10. API v2 Feature Flag Implementation
|
|
|
|
**Date:** 2026-04-04
|
|
**Status:** Accepted
|
|
**Authors:** AI Agent
|
|
|
|
## Context
|
|
|
|
The DanceLessonsCoach application needed to add a new API version (v2) that provides different greeting behavior while maintaining backward compatibility with the existing v1 API. The v2 API should only be available when explicitly enabled via a feature flag.
|
|
|
|
## Decision
|
|
|
|
Implement API v2 with the following characteristics:
|
|
|
|
1. **Separate Service Implementation**: Create a new `ServiceV2` that implements different greeting logic
|
|
2. **Feature Flag Control**: Add a configuration flag `api.v2_enabled` to control v2 availability
|
|
3. **Environment Variable Support**: Allow enabling via `DLC_API_V2_ENABLED` environment variable
|
|
4. **Default Disabled**: v2 API is disabled by default to maintain backward compatibility
|
|
5. **Separate Routing**: v2 endpoints use `/api/v2` prefix, separate from `/api/v1`
|
|
|
|
## Implementation Details
|
|
|
|
### Service Layer
|
|
|
|
- **New Service**: `pkg/greet/greet_v2.go` with `ServiceV2` struct
|
|
- **New Interface**: `GreeterV2` interface with `GreetV2()` method
|
|
- **Different Behavior**: Returns "Hello my friend <name>!" instead of "Hello <name>!"
|
|
- **Empty Name Handling**: Returns "Hello my friend!" when name is empty
|
|
|
|
### API Layer
|
|
|
|
- **New Handler**: `pkg/greet/api_v2.go` with `apiV2GreetHandler` struct
|
|
- **New Interface**: `ApiV2Greet` interface with `RegisterRoutes()` method
|
|
- **POST Endpoint**: `/api/v2/greet` expects JSON body with `name` field
|
|
- **JSON Response**: Returns `{"message": "<greeting>"}` format
|
|
|
|
### Configuration
|
|
|
|
- **New Config Struct**: `APIConfig` in `pkg/config/config.go`
|
|
- **Feature Flag**: `V2Enabled bool` field
|
|
- **Environment Variable**: `DLC_API_V2_ENABLED` binding
|
|
- **Default Value**: `false` (disabled by default)
|
|
- **Config Method**: `GetV2Enabled()` method on `Config` struct
|
|
|
|
### Server Integration
|
|
|
|
- **Conditional Routing**: v2 routes only registered when `config.GetV2Enabled()` returns true
|
|
- **Separate Registration**: `registerApiV2Routes()` method in server
|
|
- **Same Middleware**: v2 routes use same middleware stack as v1
|
|
- **Graceful Coexistence**: Both v1 and v2 can run simultaneously
|
|
|
|
### Testing
|
|
|
|
- **Unit Tests**: `pkg/greet/greet_v2_test.go` with table-driven tests
|
|
- **BDD Tests**: Extended `features/greet.feature` with v2 scenarios
|
|
- **Step Definitions**: Added v2-specific steps in `pkg/bdd/steps/steps.go`
|
|
- **Test Server**: Modified test server to enable v2 by default for testing
|
|
|
|
## Consequences
|
|
|
|
### Positive
|
|
|
|
- **Backward Compatibility**: v1 API continues to work unchanged
|
|
- **Feature Flag Control**: v2 can be enabled/disabled without code changes
|
|
- **Clean Separation**: v1 and v2 implementations are independent
|
|
- **Test Coverage**: Comprehensive BDD tests validate both versions
|
|
- **Configuration Flexibility**: Can be controlled via config file or environment variables
|
|
|
|
### Negative
|
|
|
|
- **Increased Complexity**: More code paths to maintain
|
|
- **Configuration Management**: Additional configuration option to document
|
|
- **Testing Overhead**: Need to test both enabled and disabled states
|
|
- **Deployment Considerations**: Need to ensure feature flag is set correctly in production
|
|
|
|
## Alternatives Considered
|
|
|
|
### 1. Always Enable v2
|
|
- **Rejected**: Would break backward compatibility
|
|
- **Reason**: Customers might not be ready for API changes
|
|
|
|
### 2. Replace v1 with v2
|
|
- **Rejected**: Would be a breaking change
|
|
- **Reason**: Violates semantic versioning principles
|
|
|
|
### 3. Use URL Query Parameter
|
|
- **Rejected**: Less clean API design
|
|
- **Reason**: Version should be in URL path, not query string
|
|
|
|
### 4. Use Header-Based Versioning
|
|
- **Rejected**: More complex for clients
|
|
- **Reason**: URL-based versioning is more RESTful and discoverable
|
|
|
|
## Validation
|
|
|
|
### Test Results
|
|
|
|
```bash
|
|
# Unit tests pass
|
|
go test ./pkg/greet/...
|
|
|
|
# BDD tests pass
|
|
go test ./features/... -v
|
|
|
|
# All scenarios pass:
|
|
- Default greeting (v1)
|
|
- Personalized greeting (v1)
|
|
- v2 greeting with JSON POST request
|
|
- v2 default greeting with empty name
|
|
- Health check returns healthy status
|
|
```
|
|
|
|
### Manual Testing
|
|
|
|
```bash
|
|
# Test v2 disabled (default)
|
|
curl -X POST http://localhost:8080/api/v2/greet -H "Content-Type: application/json" -d '{"name":"John"}'
|
|
# Expected: 404 Not Found
|
|
|
|
# Test v2 enabled
|
|
DLC_API_V2_ENABLED=true go run ./cmd/server
|
|
curl -X POST http://localhost:8080/api/v2/greet -H "Content-Type: application/json" -d '{"name":"John"}'
|
|
# Expected: {"message":"Hello my friend John!"}
|
|
|
|
# Test v1 still works
|
|
curl http://localhost:8080/api/v1/greet/John
|
|
# Expected: {"message":"Hello John!"}
|
|
```
|
|
|
|
## Migration Path
|
|
|
|
1. **Deploy with v2 Disabled**: Initial deployment keeps v2 disabled
|
|
2. **Enable in Staging**: Test v2 in staging environment
|
|
3. **Gradual Rollout**: Enable v2 for select customers
|
|
4. **Monitor**: Track usage and performance
|
|
5. **Full Enable**: Enable v2 for all customers when ready
|
|
6. **Deprecation**: Eventually deprecate v1 (future decision)
|
|
|
|
## Future Considerations
|
|
|
|
- **Deprecation Timeline**: When to deprecate v1
|
|
- **Version Negotiation**: Content negotiation for API versions
|
|
- **OpenAPI Documentation**: Update Swagger/OpenAPI docs for v2
|
|
- **Client SDKs**: Update client libraries to support v2
|
|
- **Metrics**: Add metrics to track v1 vs v2 usage
|
|
|
|
## References
|
|
|
|
- [Semantic Versioning](https://semver.org/)
|
|
- [REST API Versioning Best Practices](https://restfulapi.net/versioning/)
|
|
- [Feature Flags Pattern](https://martinfowler.com/articles/feature-toggles.html)
|
|
|
|
## Changelog Entry
|
|
|
|
```
|
|
### 2026-04-04 - API v2 Implementation
|
|
- ✅ Added /api/v2/greet POST endpoint with JSON request/response
|
|
- ✅ Implemented ServiceV2 with "Hello my friend <name>!" greeting format
|
|
- ✅ Added api.v2_enabled feature flag (default: false)
|
|
- ✅ Extended BDD tests to cover v2 scenarios
|
|
- ✅ Maintained full backward compatibility with v1 API
|
|
- ✅ Added DLC_API_V2_ENABLED environment variable support
|
|
``` |