feat: implement input validation for API v2

- Added go-playground/validator dependency

- Created pkg/validation/ package with custom validator wrapper

- Implemented request validation for v2 greet endpoint

- Added structured validation error responses

- Extended BDD tests to cover validation scenarios

- Updated AGENTS.md with v2 API documentation

- Created ADR 0011-validation-library-selection.md

- Simplified server handler creation code

- Updated CHANGELOG with implementation details
This commit is contained in:
2026-04-04 21:08:13 +02:00
parent 875eb09fb7
commit d3b6d190d1
11 changed files with 489 additions and 14 deletions

View File

@@ -0,0 +1,198 @@
# 11. Validation Library Selection
**Date:** 2026-04-04
**Status:** Proposed
**Authors:** AI Agent
## Context
The DanceLessonsCoach project needs to add input validation for API requests, particularly for the new v2 API endpoints that accept JSON payloads. Currently, there is no structured validation in place, which could lead to invalid data being processed by the system.
## Decision Drivers
1. **Maturity and Stability**: Need a well-established library with proven track record
2. **Community Support**: Active maintenance and community adoption
3. **Feature Completeness**: Support for common validation scenarios (required fields, string lengths, numeric ranges, etc.)
4. **Performance**: Minimal impact on request processing times
5. **Integration**: Easy to integrate with existing Chi router and JSON handling
6. **Error Handling**: Clear, actionable error messages for API consumers
7. **Extensibility**: Ability to add custom validation rules
## Considered Options
### 1. go-playground/validator (v10)
**Overview:** The most widely adopted validation library for Go, using struct tags for rule definition.
**Pros:**
-**Most mature and stable** - Used in production by thousands of projects
-**Extensive built-in validators** - Covers 90%+ of common validation needs
-**Large community** - Active GitHub repository with frequent updates
-**Good documentation** - Comprehensive examples and guides
-**Struct tag-based** - Clean separation of validation rules from business logic
-**Custom validators** - Support for adding project-specific validation rules
-**Cross-field validation** - Can validate relationships between fields
-**JSON Schema generation** - Can generate schemas from validation tags
**Cons:**
-**Reflection-based** - Slightly slower than compile-time alternatives
-**Tag syntax** - Can become verbose for complex validations
-**Error messages** - Requires some customization for API-friendly errors
### 2. ozzo-validation
**Overview:** Configurable and extensible data validation using code-based rules.
**Pros:**
-**Code-based validation** - Rules defined in Go code rather than tags
-**Customizable errors** - Better control over error message formatting
-**Extensible** - Easy to add new validation rules
-**Good performance** - Faster than reflection-based validators
**Cons:**
-**Less mature** - Smaller community than go-playground/validator
-**More verbose** - Requires more code for common validations
-**Learning curve** - Different approach than tag-based validation
### 3. Valgo
**Overview:** Type-safe, expressive, and extensible validator library.
**Pros:**
-**Type-safe** - Compile-time type checking
-**Modern API** - Clean, expressive syntax
-**Good performance** - Type-safe approach can be faster
-**Extensible** - Easy to add custom validators
**Cons:**
-**Newer library** - Less battle-tested than go-playground/validator
-**Smaller community** - Fewer resources and examples available
-**Breaking changes** - Still evolving API
### 4. govalid
**Overview:** Compile-time validation library that generates validation code.
**Pros:**
-**Compile-time generation** - Up to 45x faster than reflection-based
-**No reflection overhead** - Better performance in hot paths
-**Type-safe** - Compile-time checking
**Cons:**
-**Build complexity** - Requires code generation step
-**Less flexible** - Harder to add runtime validation rules
-**Smaller ecosystem** - Fewer built-in validators
## Decision Outcome
**Chosen option:** `go-playground/validator` (v10)
**Rationale:**
1. **Proven Track Record**: Used successfully in countless production Go applications
2. **Community Support**: Large ecosystem, active maintenance, and extensive documentation
3. **Feature Completeness**: Covers all our current and anticipated validation needs
4. **Integration**: Works seamlessly with our existing struct-based JSON handling
5. **Performance**: While not the fastest, the performance impact is negligible for our use case
6. **Error Handling**: Can be customized to provide API-friendly error messages
7. **Extensibility**: Supports custom validators for project-specific needs
## Implementation Plan
### Phase 1: Integration Setup
1. Add `github.com/go-playground/validator/v10` dependency
2. Create validation utility package in `pkg/validation/`
3. Set up validator instance with custom error handling
4. Add common validation tags and error message mappings
### Phase 2: API v2 Validation
1. Add validation to `greetRequest` struct in `api_v2.go`
2. Implement request validation middleware
3. Create custom error responses for validation failures
4. Add comprehensive validation tests
### Phase 3: Extend to Other Endpoints
1. Apply validation to existing v1 endpoints (optional)
2. Add validation to health/readiness endpoints (if needed)
3. Create validation documentation for API consumers
### Phase 4: Advanced Features
1. Add custom validators for business rules
2. Implement internationalized error messages
3. Add validation performance monitoring
## Validation Strategy
### Request Validation Pattern
```go
// Define validated struct
type GreetRequest struct {
Name string `json:"name" validate:"required,min=1,max=100"`
}
// Validate in handler
func (h *apiV2GreetHandler) handleGreetPost(w http.ResponseWriter, r *http.Request) {
var req GreetRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
// Handle JSON decode error
return
}
if err := validator.Validate(req); err != nil {
// Return validation error response
return
}
// Process valid request
message := h.greeter.GreetV2(r.Context(), req.Name)
h.writeJSONResponse(w, message)
}
```
### Error Response Format
```json
{
"error": "validation_failed",
"message": "Invalid request data",
"details": [
{
"field": "name",
"error": "required",
"message": "Name is required"
}
]
}
```
## Migration Path
1. **Initial Integration**: Add validator to v2 endpoints only
2. **Testing**: Validate performance and error handling
3. **Documentation**: Update API docs with validation requirements
4. **Gradual Rollout**: Apply to other endpoints as needed
5. **Monitoring**: Track validation failures and adjust rules
## Future Considerations
- **Performance Optimization**: If validation becomes bottleneck, consider compile-time alternatives
- **Schema Generation**: Generate OpenAPI schemas from validation tags
- **Internationalization**: Support multiple languages for error messages
- **Rule Management**: Externalize validation rules for dynamic configuration
## References
- [go-playground/validator GitHub](https://github.com/go-playground/validator)
- [Validator Documentation](https://pkg.go.dev/github.com/go-playground/validator/v10)
- [Go Validation Libraries Comparison](https://leapcell.io/blog/exploring-golang-s-validation-libraries)
## Changelog Entry
```
### 2026-04-04 - Validation Library Selection
- ✅ Selected go-playground/validator for input validation
- ✅ Created ADR 0011-validation-library-selection.md
- ✅ Planned integration strategy for API validation
- ✅ Designed error response format for validation failures
```

View File

@@ -69,6 +69,7 @@ Chosen option: "[Option 1]" because [justification]
* [0008-bdd-testing.md](0008-bdd-testing.md) - Adopt BDD with Godog for behavioral testing
* [0009-hybrid-testing-approach.md](0009-hybrid-testing-approach.md) - Combine BDD and Swagger-based testing
* [0010-api-v2-feature-flag.md](0010-api-v2-feature-flag.md) - API v2 implementation with feature flag control
* [0011-validation-library-selection.md](0011-validation-library-selection.md) - Selection of go-playground/validator for input validation
## How to Add a New ADR