Appearance
Schema: Data Validation
Konfigo's validate
directives enforce rules and constraints on processed configuration data, ensuring integrity before final output. Validation executes after variables, generators, and transformations are complete.
Validation Structure
yaml
validate:
- path: "config.path.to.validate"
rules:
required: true
type: "string"
minLength: 3
regex: "^[a-zA-Z][a-zA-Z0-9_]*$"
Fields
path
(Required): Dot-separated path to configuration valuerules
(Required): Object containing validation constraints
Validation Rules
Core Rules
required
(boolean, default: false)
- When
true
, value must exist at path - When
false
or missing, other rules skipped if path not found
type
(string)
- Enforces specific data type
- Supported types:
"string"
,"number"
,"integer"
,"boolean"
,"slice"
,"map"
String Rules
minLength
(integer)
- Minimum string length
regex
(string)
- ECMA 262 JavaScript-style regular expression pattern
enum
(array of strings)
- Value must match one of the provided options
Numeric Rules
min
(number)
- Minimum value (inclusive) for numbers and integers
max
(number)
- Maximum value (inclusive) for numbers and integers
Examples from Tests
Basic Configuration Validation
Input Configuration:
yaml
service:
name: "user-service"
port: 8080
environment: "production"
database:
host: "db-server"
port: 5432
Validation Schema:
yaml
validate:
- path: "service.name"
rules:
required: true
type: "string"
minLength: 3
regex: "^[a-zA-Z][a-zA-Z0-9_-]*$"
- path: "service.port"
rules:
required: true
type: "number"
min: 1024
max: 65535
- path: "service.environment"
rules:
type: "string"
enum: ["development", "staging", "production"]
Complex Nested Validation
Schema with Multiple Constraints:
yaml
validate:
# Database credentials validation
- path: "database.credentials.username"
rules:
required: true
type: "string"
minLength: 3
regex: "^[a-zA-Z][a-zA-Z0-9_]*$"
- path: "database.credentials.password"
rules:
required: true
type: "string"
minLength: 8
regex: "^[a-zA-Z0-9_@$!%*?&]{8,}$"
# Array validation
- path: "features.features"
rules:
type: "slice"
# Multiple constraints on same field
- path: "service.port"
rules:
required: true
type: "number"
min: 1024
max: 65535
# Floating point validation
- path: "timeouts.connect"
rules:
type: "number"
min: 0.1
max: 60.0
Optional Field Validation
Configuration:
yaml
api:
endpoint: "https://api.example.com"
timeout: 30
# apiKey is optional
cache:
enabled: true
ttl: 300
Schema:
yaml
validate:
# Required fields
- path: "api.endpoint"
rules:
required: true
type: "string"
regex: "^https?://"
- path: "api.timeout"
rules:
required: true
type: "number"
min: 1
max: 300
# Optional field with validation when present
- path: "api.apiKey"
rules:
required: false # Optional
type: "string"
minLength: 32
regex: "^[a-f0-9]{32}$" # 32-char hex
- path: "cache.enabled"
rules:
type: "boolean"
- path: "cache.ttl"
rules:
type: "number"
min: 60
max: 3600
Environment-Specific Validation
Development vs Production Constraints:
yaml
# Different validation based on environment
vars:
- name: "ENV"
fromEnv: "ENVIRONMENT"
defaultValue: "development"
validate:
- path: "database.ssl"
rules:
required: true
type: "boolean"
# Stricter password rules in production
- path: "database.password"
rules:
required: true
type: "string"
minLength: 12 # Longer in production
regex: "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]{12,}$"
# Debug mode validation
- path: "app.debug"
rules:
type: "boolean"
Validation Processing
Order of Operations
- Path Resolution: Check if configuration value exists at path
- Required Check: If
required: true
and path missing, fail immediately - Skip Missing: If path missing and not required, skip other rules
- Type Validation: Check data type if specified
- Constraint Validation: Apply min/max, minLength, enum, regex rules
Example Processing Flow
yaml
# Configuration:
service:
port: "8080" # String instead of number
# Validation:
- path: "service.port"
rules:
required: true
type: "number"
min: 1024
# Processing:
# 1. Path "service.port" exists ✓
# 2. required: true and value exists ✓
# 3. type: "number" but value is string ✗ FAIL
# 4. min: 1024 not checked (type failed)
Error Scenarios from Tests
Type Mismatches
yaml
# ERROR: Expected number, got string
service:
port: "eight-thousand"
validate:
- path: "service.port"
rules:
type: "number"
Range Violations
yaml
# ERROR: Value 99999 exceeds max 65535
service:
port: 99999
validate:
- path: "service.port"
rules:
type: "number"
max: 65535
Pattern Mismatches
yaml
# ERROR: Invalid username format
user:
name: "123invalid"
validate:
- path: "user.name"
rules:
regex: "^[a-zA-Z][a-zA-Z0-9_]*$"
Enum Violations
yaml
# ERROR: "test" not in allowed values
environment: "test"
validate:
- path: "environment"
rules:
enum: ["development", "staging", "production"]
Advanced Validation Patterns
Multi-Field Dependencies
While Konfigo doesn't support cross-field validation directly, you can use generators and transformations to prepare validation:
yaml
# Generate computed field for validation
generators:
- type: "concat"
targetPath: "validation.dbConnection"
format: "{host}:{port}"
sources:
host: "database.host"
port: "database.port"
validate:
- path: "validation.dbConnection"
rules:
regex: "^[a-zA-Z0-9.-]+:[0-9]+$"
Conditional Validation with Variables
yaml
vars:
- name: "REQUIRE_SSL"
fromEnv: "PROD_MODE"
defaultValue: "false"
# Set required SSL field based on environment
transform:
- type: "setValue"
path: "database.sslRequired"
value: "${REQUIRE_SSL}"
validate:
- path: "database.sslRequired"
rules:
type: "boolean"
# Only validate SSL cert if required
- path: "database.sslCert"
rules:
required: false # Handle conditionally in app logic
type: "string"
Best Practices
- Start Simple: Begin with basic required/type validation
- Gradual Enhancement: Add constraints incrementally
- Test Edge Cases: Validate with invalid data to verify error handling
- Document Constraints: Explain validation rules in configuration templates
- Environment Awareness: Consider different validation needs per environment
- Error Messages: Validation errors include path and rule details
- Example:
min: 0
- Example:
max
(number):- For values of
type: "number"
or"integer"
. The value must be less than or equal tomax
. - Example:
max: 100
- For values of
minLength
(integer):- For values of
type: "string"
. The string's length must be greater than or equal tominLength
. - Example:
minLength: 3
- For values of
enum
(list of strings):- For values of
type: "string"
. The string value must be one of the values present in theenum
list. - Example:
enum: ["production", "staging", "development"]
- For values of
regex
(string):- For values of
type: "string"
. The string value must match the provided ECMA 262 (JavaScript-style) regular expression. - Example:
regex: "^\\d{3}-\\d{2}-\\d{4}$"
(for a US SSN format)
- For values of
How Validation Works
- Konfigo iterates through each validation group defined in the
validate
list. - For each group, it attempts to retrieve the value from the configuration at the specified
path
. - Existence Check:
- If the
rules.required
istrue
and the value is not found, validation fails immediately for this group. - If the value is not found and
rules.required
isfalse
(or not set), this validation group is skipped, and Konfigo moves to the next one.
- If the
- Rule Application: If the value is found, Konfigo applies all specified rules in the
rules
object to it.- Type Check: If
type
is specified, it's checked first. If it fails, an error is reported. - Other Rules: Subsequent rules (
min
,max
,minLength
,enum
,regex
) are checked. These rules generally assume the type check (if specified) has passed or that the value is of a compatible type (e.g.,min
expects a number).
- Type Check: If
- If any rule fails, Konfigo stops processing and reports a validation error, typically indicating the path, the problematic value, and the rule that failed.
- If all validation groups pass, the configuration is considered valid according to the schema.
Examples
Example 1: Basic Service Configuration Validation
yaml
# schema.yml
validate:
- path: "service.name"
rules:
required: true
type: "string"
minLength: 3
- path: "service.port"
rules:
required: true
type: "integer"
min: 1024
max: 65535
- path: "service.environment"
rules:
type: "string"
enum: ["dev", "staging", "prod"]
- path: "service.apiKey"
rules:
required: false # Optional API key
type: "string"
regex: "^[a-f0-9]{32}$" # Example: 32-char hex string
Valid Configuration (config.yml
):
yaml
service:
name: "user-auth"
port: 8080
environment: "prod"
apiKey: "abcdef0123456789abcdef0123456789"
Invalid Configuration (and why):
yaml
service:
name: "db" # Fails service.name minLength: 3
# port is missing - Fails service.port required: true
environment: "testing" # Fails service.environment enum
Example 2: Validating Nested Structures and Optional Fields
yaml
# schema.yml
validate:
- path: "database.host"
rules:
required: true
type: "string"
- path: "database.port"
rules:
required: true
type: "integer"
min: 1
max: 65535
- path: "database.credentials.username"
rules:
required: true
type: "string"
- path: "database.credentials.password" # Password is required
rules:
required: true
type: "string"
minLength: 8
- path: "featureFlags.betaEnabled" # Optional boolean
rules:
type: "boolean"
- path: "timeouts.read"
rules:
type: "number"
min: 0.5 # e.g., 0.5 seconds
max: 60
Valid Configuration (config.json
):
json
{
"database": {
"host": "db.example.com",
"port": 5432,
"credentials": {
"username": "admin",
"password": "complex_password123"
}
},
"featureFlags": {
"betaEnabled": true
},
"timeouts": {
"read": 30
}
}
If timeouts.read
was "fast"
, it would fail the type: "number"
check. If database.port
was 99999
, it would fail the max: 65535
check.
By defining comprehensive validation rules, you can significantly increase the reliability and robustness of your application's configuration.