Validation
ZyraForm supports Zod-like validation rules that are automatically applied based on your schema definition.
String Validations
Section titled “String Validations”Email Validation
Section titled “Email Validation”.text("email").email().notNull()
// Error: "email must be a valid email"URL Validation
Section titled “URL Validation”.text("website").url().nullable()
// Error: "website must be a valid URL"HTTP/HTTPS URL Validation
Section titled “HTTP/HTTPS URL Validation”.text("api_endpoint").httpUrl()
// Error: "api_endpoint must be a valid HTTP/HTTPS URL"UUID Validation
Section titled “UUID Validation”.text("user_id").uuid()
// Error: "user_id must be a valid UUID"Length Validations
Section titled “Length Validations”.text("username").minLength(3).maxLength(20)
// Error: "username must be at least 3 characters"// Error: "username must be at most 20 characters"
.text("code").exactLength(6)
// Error: "code must be exactly 6 characters"String Content Validations
Section titled “String Content Validations”.text("domain").startsWith("https://").text("slug").endsWith(".com").text("description").includes("important").text("username").lowercase().text("api_key").uppercase()Regex Validation
Section titled “Regex Validation”.text("phone").regex("^\\+?[1-9]\\d{1,14}$", error: "Invalid phone number")
.text("username").regex("^[a-zA-Z0-9_]+$", error: "Username must contain only letters, numbers, and underscores")Number Validations
Section titled “Number Validations”Integer Validations
Section titled “Integer Validations”.integer("age").positive().intMin(18).intMax(120)
// Error: "age must be positive"// Error: "age must be at least 18"// Error: "age must be at most 120"
.integer("page").even().integer("row").odd().integer("balance").negative()Double Validations
Section titled “Double Validations”.real("price").double().positive().minimum(0.01).maximum(9999.99)
// Error: "price must be positive"// Error: "price must be at least 0.01"// Error: "price must be at most 9999.99"Custom Validation
Section titled “Custom Validation”Create custom validation rules with error messages:
.text("password") .minLength(8) .custom("Password must contain uppercase, lowercase, and number") { value in guard let password = value as? String else { return false } let hasUppercase = password.range(of: "[A-Z]", options: .regularExpression) != nil let hasLowercase = password.range(of: "[a-z]", options: .regularExpression) != nil let hasNumber = password.range(of: "\\d", options: .regularExpression) != nil return hasUppercase && hasLowercase && hasNumber }
.real("price").double() .positive() .custom("Price must be at least 0.01") { value in if let price = value as? Double { return price >= 0.01 } return false }Multiple Validations
Section titled “Multiple Validations”Chain multiple validations:
.text("email") .email() .notNull() .minLength(5) .maxLength(255)
.integer("age") .positive() .intMin(13) .intMax(120) .custom("Age must be a valid integer") { value in value is Int }Validation Examples
Section titled “Validation Examples”User Registration Form
Section titled “User Registration Form”let RegistrationSchema = ExtendedTable( name: "\(AppConfig.dbPrefix)users", columns: [ .text("email") .email() .notNull(), .text("username") .minLength(3) .maxLength(20) .regex("^[a-zA-Z0-9_]+$", error: "Username must contain only letters, numbers, and underscores") .notNull(), .text("password") .minLength(8) .custom("Password must contain uppercase, lowercase, and number") { value in guard let password = value as? String else { return false } let hasUppercase = password.range(of: "[A-Z]", options: .regularExpression) != nil let hasLowercase = password.range(of: "[a-z]", options: .regularExpression) != nil let hasNumber = password.range(of: "\\d", options: .regularExpression) != nil return hasUppercase && hasLowercase && hasNumber } .notNull(), .text("age") .int() .positive() .intMin(18) .intMax(120) .nullable(), .text("website") .url() .nullable() ])Product Form
Section titled “Product Form”let ProductsSchema = ExtendedTable( name: "\(AppConfig.dbPrefix)products", columns: [ .text("name") .minLength(1) .maxLength(100) .notNull(), .text("sku") .regex("^[A-Z]{3}-\\d{4}$", error: "SKU must be in format ABC-1234") .notNull(), .real("price") .double() .positive() .minimum(0.01) .maximum(9999.99) .custom("Price must be at least 0.01") { value in if let price = value as? Double { return price >= 0.01 } return false } .notNull(), .text("category") .custom("Category must be one of: electronics, clothing, books") { value in guard let category = value as? String else { return false } return ["electronics", "clothing", "books"].contains(category) } .notNull() ])Error Messages
Section titled “Error Messages”Default Error Messages
Section titled “Default Error Messages”ZyraForm provides default error messages for all validation rules:
- Required:
"{field} is required" - Email:
"{field} must be a valid email" - URL:
"{field} must be a valid URL" - Min length:
"{field} must be at least {min} characters" - Max length:
"{field} must be at most {max} characters" - Positive:
"{field} must be positive" - Range:
"{field} must be at least {min}"or"{field} must be at most {max}"
Custom Error Messages
Section titled “Custom Error Messages”Provide custom error messages:
.text("password") .custom("Password must be at least 8 characters with uppercase, lowercase, and number") { value in // validation logic }
.text("sku") .regex("^[A-Z]{3}-\\d{4}$", error: "SKU must be in format ABC-1234")Accessing Errors
Section titled “Accessing Errors”Check for Errors
Section titled “Check for Errors”if form.hasError("email") { // Show error}
let errorCount = form.errors.errorCountlet allErrors = form.errors.allErrorsGet Error Message
Section titled “Get Error Message”let emailError = form.getError("email")// Returns: Optional<String>
if let error = form.errors["email"] { print(error)}Display All Errors
Section titled “Display All Errors”ForEach(form.errors.fields, id: \.self) { field in Text(form.errors[field] ?? "") .foregroundColor(.red) .font(.caption)}Validation Modes
Section titled “Validation Modes”Control when validation occurs:
// Validate on every change.mode(.onChange)
// Validate on blur.mode(.onBlur)
// Validate on submit only.mode(.onSubmit)
// Validate once touched.mode(.onTouched)Next Steps
Section titled “Next Steps”- Form Components - Display validation errors in forms
- Conditional Fields - Show fields based on validation state