A-la-carte
A-la-carte validation allows you to define constraints dynamically within your event handlers, providing maximum flexibility for validation scenarios that don't warrant permanent constraint definitions. This approach is perfect for:
API endpoints with specific validation requirements
Form processing with dynamic validation rules
Data import/export operations with varying formats
Administrative functions with custom validation logic
Temporary or one-off validation scenarios
Overview
With a-la-carte validation, you can:
Create constraints on-the-fly within handler methods
Store constraint definitions in databases, JSON files, or services
Dynamically build validation rules based on business logic
Validate any struct, object, or request collection
Control exactly which fields to validate using inclusion/exclusion parameters
Basic A-la-carte Validation
Simple Request Collection Validation
if ( !validationResult.hasErrors() ) {
var newUser = userService.createUser(
username = rc.username,
email = rc.email,
password = rc.password
);
prc.response.setData( newUser );
} else {
prc.response
.setError( true )
.addMessage( validationResult.getAllErrors() )
.setStatusCode( 400 )
.setStatusText( "Validation failed" );
}Exception-Based Validation
For cleaner API code, use validateOrFail() to automatically throw exceptions on validation failure:
var user = userService.register( rc );
return event.renderData(
statusCode = 201,
data = { user = user, message = "Registration successful" }
);
} catch( ValidationException e ) {
return event.renderData(
statusCode = 422,
data = { errors = deserializeJSON( e.extendedInfo ) }
);
}Field Inclusion and Exclusion
Control exactly which fields get validated using the includeFields and excludeFields parameters:
var fieldsToValidate = "firstName,lastName,email,phone,website";
// Only validate profile fields, skip password-related fields
var result = validate(
target = rc,
constraints = constraints,
includeFields = fieldsToValidate
);
if ( result.hasErrors() ) {
prc.errors = result.getAllErrors();
return event.setView( "users/profile" );
}
userService.updateProfile( rc );
flash.put( "success", "Profile updated successfully" );
return event.setView( "users/profile" );Dynamic Constraint Building
Build constraints programmatically based on business logic or user roles:
// Add role-specific constraints
if ( rc.role == "admin" ) {
constraints.adminCode = { required = true, size = "10" };
constraints.permissions = { required = true, type = "array" };
}
if ( rc.role == "employee" ) {
constraints.department = { required = true, inList = "HR,IT,Sales,Marketing" };
constraints.employeeId = { required = true, regex = "^EMP\d{6}$" };
}
// Add password constraints if creating new account
if ( !structKeyExists( rc, "userId" ) ) {
constraints.password = { required = true, size = "8..128" };
constraints.confirmPassword = { required = true, sameAs = "password" };
}
var result = validate( target = rc, constraints = constraints );
if ( result.hasErrors() ) {
prc.errors = result.getAllErrors();
return event.setView( "admin/users/form" );
}
var user = userService.createUser( rc );
flash.put( "success", "User created successfully" );
return event.relocate( "admin.users.index" );External Constraint Sources
Load constraints from external sources like databases, JSON files, or services:
var result = validate( target = rc, constraints = constraints );
if ( result.hasErrors() ) {
prc.errors = result.getAllErrors();
prc.form = formConfig;
return event.setView( "forms/custom" );
}
// Process valid form data
formService.saveFormSubmission( rc.formId, rc );
flash.put( "success", "Form submitted successfully" );
return event.relocate( "forms.thankyou" );Complex Data Structure Validation
Validate nested objects and arrays using a-la-carte constraints:
// Shipping address
"shipping.street" = { required = true, size = "5..200" },
"shipping.city" = { required = true, size = "2..100" },
"shipping.state" = { required = true, size = "2" },
"shipping.zip" = { required = true, regex = "^\d{5}(-\d{4})?$" },
// Order items (array validation)
"items.*.productId" = { required = true, type = "string" },
"items.*.quantity" = { required = true, type = "numeric", min = "1" },
"items.*.price" = { required = true, type = "numeric", min = "0.01" },
// Payment information
"payment.method" = { required = true, inList = "credit,debit,paypal" },
"payment.total" = { required = true, type = "numeric", min = "0.01" }
};
var result = validate( target = rc, constraints = constraints );
if ( result.hasErrors() ) {
prc.errors = result.getAllErrors();
return event.setView( "orders/checkout" );
}
var order = orderService.processOrder( rc );
return event.renderData(
statusCode = 201,
data = { orderId = order.id, message = "Order processed successfully" }
);Best Practices
1. Use for Specific Scenarios
A-la-carte validation is best for endpoint-specific requirements, not general business rules.
2. Keep Constraints Close to Usage
Define constraints within the handler method for better maintainability and context.
3. Leverage Field Control Parameters
Use includeFields and excludeFields to validate only relevant data.
4. Handle Complex Data Structures
Use dot notation and asterisk wildcards for nested objects and arrays.
5. Consider External Sources
For dynamic forms or configurable validation, load constraints from databases or configuration files.
6. Provide Meaningful Error Messages
Include custom error messages that guide users toward resolution.
A-la-carte validation provides the flexibility to handle unique validation scenarios while maintaining the power and consistency of CBValidation's constraint system. It's perfect for API endpoints, dynamic forms, and any situation where domain object constraints aren't sufficient or appropriate.
Last updated
Was this helpful?