Validation¶
The validation system lets you define reusable validation rules and apply them to database function parameters automatically. It is strategy-agnostic (FluentValidation, Manual, DataAnnotations, Assert) and language-agnostic — templates control the emitted syntax.
Key features
- Reusable rules — define once, apply to many parameters.
- Custom executors — point to existing functions or generate inline code.
- Multi-error collection — return all errors at once or fail-fast.
- Function-specific overrides — global rules plus per-function customization.
Basic setup¶
{
"Validation": {
"ValidationStrategy": "Manual",
"ValidationLocations": ["Controller", "Provider"],
"ValidationBehavior": {
"CollectAllErrors": true,
"ReturnType": "ValidationResult"
}
}
}
Rule definitions¶
Define rules that can be reused across parameters. Each rule carries per-strategy templates:
{
"ValidationRuleDefinitions": [
{
"Name": "CheckBusinessCode",
"Type": "Custom",
"ExecutorType": "ExistingFunction",
"ExecutorReference": "ValidationHelpers.ValidateBusinessCode",
"ErrorMessage": "Invalid business unit code",
"ErrorCode": "INVALID_BUSINESS_CODE",
"Templates": {
"FluentValidation": ".Must(ValidationHelpers.ValidateBusinessCode).WithMessage(\"Invalid business unit code\").WithErrorCode(\"INVALID_BUSINESS_CODE\")",
"Manual": {
"Check": "ValidationHelpers.ValidateBusinessCode({{.ParamName}})",
"ErrorBuilder": "new ValidationError(\"{{.ParamName}}\", \"Invalid business unit code\", \"INVALID_BUSINESS_CODE\")"
}
}
}
]
}
Rule types¶
ExecutorType |
Behavior |
|---|---|
ExistingFunction |
Calls a validation function already in your codebase (ExecutorReference). |
GenerateCode |
Emits inline validation code (GeneratedCode). |
Type is Built-in, Custom, or Generated.
Applying rules to parameters¶
Global mappings¶
Map rules to parameter names across all functions:
{
"ParameterValidationMappings": [
{ "ParameterNames": ["businessunitcode", "businesscode"], "Rules": ["CheckBusinessCode"] },
{ "ParameterNames": ["email", "emailaddress"], "Rules": ["Required", "EmailFormat", {"Name": "MaxLength", "Value": 255}] },
{ "ParameterNames": ["userid", "customerid"], "Rules": ["Required", "PositiveNumber"] }
]
}
A rule reference is either a string (rule name) or an object with parameters ({"Name": "MaxLength", "Value": 255}).
Function-specific overrides¶
Extend or override global rules for a single function:
{
"FunctionSpecificValidations": {
"CreateUser": { "age": [{"Name": "Range", "Min": 18, "Max": 120}] },
"UpdateUserEmail": { "newemail": ["Required", "EmailFormat"] }
}
}
Strategies¶
var errors = new List<ValidationError>();
if (email == null || string.IsNullOrEmpty(email))
errors.Add(new ValidationError("email", "Email is required", "REQUIRED_FIELD"));
if (!ValidationHelpers.ValidateBusinessCode(businessCode))
errors.Add(new ValidationError("businessCode", "Invalid business unit code", "INVALID_BUSINESS_CODE"));
if (errors.Any())
return BadRequest(new ValidationResult { Success = false, Errors = errors });
Behavior options¶
CollectAllErrors—truereturns all validation errors at once;falsefails on the first.ReturnType—ValidationResult(simple error array) orProblemDetails(RFC 7807).
Template placeholders¶
Available in validation rule templates:
| Placeholder | Meaning |
|---|---|
{{.ParamName}} |
Parameter name |
{{.ParamDisplayName}} |
Display name |
{{.Min}} / {{.Max}} |
Range bounds |
{{.Value}} |
Generic value (e.g. MaxLength) |
Works with context mapping¶
Validation composes with context mapping — context parameters are validated before being extracted from the context object:
{
"UseUserContext": true,
"ContextParameterMappings": [ /* ... */ ],
"Validation": {
"ParameterValidationMappings": [
{ "ParameterNames": ["userid"], "Rules": ["Required", "PositiveNumber"] }
]
}
}
Adopt gradually
Start by adding rules for critical parameters (email, ids), define custom rules for business logic, then enable CollectAllErrors for better UX. Existing code keeps working as you go.