Release v18.6.0
Summary
Implements client-side validation governed by backend FluentValidation rules. The ProxyGenerator extracts validation rules from AbstractValidator<> implementations using reflection and generates TypeScript validation code, enabling pre-flight validation before server calls without requiring version parity between ProxyGenerator and target assemblies.
Added
- TypeScript validation rules engine with fluent API similar to FluentValidation
- Core rules:
notEmpty(),notNull(),minLength(),maxLength(),length(),emailAddress(),matches(),greaterThan(),lessThan(), etc. Validator<T>class for programmatically building property validation rules withruleFor()methodPropertyRulebase class and rule-specific implementations with default error messageswithMessage()support onRuleBuilderfor custom validation error messages
- Core rules:
QueryValidatorfor validating query parameters (extendsValidator<T>)ValidationRulesExtractorin ProxyGenerator to extract rules from FluentValidation validators using pure reflection and string-based type checking- Validation descriptors (
ValidationRuleDescriptor,PropertyValidationDescriptor) for template generation
Example
Backend validator:
public class CreateUserValidator : BaseValidator<CreateUserCommand>
{
public CreateUserValidator()
{
RuleFor(x => x.Email).NotEmpty().WithMessage("Email address is required");
RuleFor(x => x.Age).GreaterThanOrEqual(18);
}
}Generated TypeScript:
export class CreateUserCommandValidator extends CommandValidator<ICreateUserCommand> {
constructor() {
super();
this.ruleFor(c => c.email).notEmpty().withMessage('Email address is required');
this.ruleFor(c => c.age).greaterThanOrEqual(18); // Uses default: "'age' must be greater than or equal to 18."
}
}Client validation runs automatically:
const command = new CreateUserCommand();
command.email = ""; // Invalid
const result = await command.execute(); // Fails client-side validation
// result.isValid === false
// result.validationResults contains error details with appropriate messagesOriginal prompt
This section details on the original issue you should resolve
<issue_title>Support for client validation rules governed by the backend</issue_title>
<issue_description>The backend should govern all validation rules. But these should be automatically be picked up by the proxy generator and added to the proxy objects so that the client can perform validation.We can only support out of the box validation rules and not type of .Must() rules. That means the out-of-the-box FluentValidation rules that look at input validation.
Frontend rules engine
We need a simple TypeScript based rules engine sitting in the Arc project under the validation folder. There is stuff there already, but feel free to expand on it, or replace whatever makes sense.
It should be possible to use the rule engine programmatically and should feel similar to how FluentValidation works with its fluent interface for building rules for a type and its properties. It can leverage the PropertyPath resolver proxy handler that we have in @cratis/fundamentals (https://github.com/Cratis/Fundamentals/blob/main/Source/JavaScript/PropertyPathResolverProxyHandler.ts) to create a nice fluent interface for being able o type safe specify which properties to add a rule to.Make it extensible and follow the same pattern as FluentValidation where the rules are extension methods. Leverage abstract classes for interfaces if needed.
ProxyGenerator
The Proxy generator needs to then understand anything that implements an
AbstractValidator<>for the type and use reflection to understand what rules to apply.The TypeScript code has the concept of a CommandValidator that implements the Validator, this is already present in the
command.hbs. This is the thing that needs to contain the generated rules.We need a similar thing for the
query.hbsand a similarQueryValidator.Commands & Queries
Before we execute commands or perform queries towards the server, we should run the associated validator. The result should still be a
CommandResultor aQueryResultand we would then fill in the validation result of these correctly.</issue_description>
Comments on the Issue (you are @copilot in this section)
- Fixes #427
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.