Validation Pipelines

Create composable validation workflows with conditional steps and complex validation chains.

What are Validation Pipelines?

Validation Pipelines in Validixty allow you to create complex validation workflows that can include conditional steps, parallel processing, and composable validation chains. This is perfect for multi-step validation processes where different validations need to be applied based on previous results or data conditions.

Why Use Validation Pipelines?

  • Complex Workflows: Handle multi-step validation processes
  • Conditional Logic: Apply validations based on conditions
  • Composable: Build reusable validation components
  • Performance: Parallel processing capabilities

Before Using Validixty

Without validation pipelines, complex workflows might look like this:

public ValidationResult ValidateUserRegistration(UserRegistration user)
{
    var errors = new List();

    // Step 1: Basic validation
    if (string.IsNullOrEmpty(user.Email))
        errors.Add("Email is required");

    if (string.IsNullOrEmpty(user.Password))
        errors.Add("Password is required");

    if (errors.Any()) return new ValidationResult(false, string.Join("; ", errors));

    // Step 2: Format validation (only if basic passed)
    if (!Regex.IsMatch(user.Email, "^[^@\\s]+@[^@\\s]+\\.[^@\\s]+$"))
        errors.Add("Invalid email format");

    if (user.Password.Length < 8)
        errors.Add("Password too short");

    if (errors.Any()) return new ValidationResult(false, string.Join("; ", errors));

    // Step 3: Business rules (only if format passed)
    if (user.IsBusinessUser)
    {
        if (string.IsNullOrEmpty(user.CompanyName))
            errors.Add("Company name required for business users");

        if (string.IsNullOrEmpty(user.TaxId))
            errors.Add("Tax ID required for business users");
    }

    return errors.Any() ? new ValidationResult(false, string.Join("; ", errors))
                       : new ValidationResult(true, "Valid");
}

After Using Validixty

With Validixty's Validation Pipelines, the same workflow becomes clean and maintainable:

using Validixty.Core;

var pipeline = ValidationPipeline.Create()
    .AddStep(new EmailAddressValidator(), "Email", obj => GetPropertyValue(obj, "Email"))
    .AddStep(new PasswordValidator(), "Password", obj => GetPropertyValue(obj, "Password"))
    .When(obj => GetPropertyValue(obj, "IsBusinessUser"),
          new BusinessValidator(), "BusinessInfo", obj => obj)
    .Build();

var result = pipeline.Execute(userObject);

How It Saves Time

  • Eliminates nested conditions: Clean, linear pipeline definition
  • Reusable components: Build once, use everywhere
  • Easier testing: Test individual pipeline steps
  • Better maintainability: Clear separation of concerns

Usage Examples

Basic Pipeline Creation

var basicPipeline = ValidationPipeline.Create()
    .AddStep(new NameValidator(), "Name", obj => obj.Name)
    .AddStep(new EmailAddressValidator(), "Email", obj => obj.Email)
    .AddStep(new PhoneNumberValidator(), "Phone", obj => obj.Phone)
    .Build();

var result = basicPipeline.Execute(userObject);

Conditional Pipeline Steps

var conditionalPipeline = ValidationPipeline.Create()
    .AddStep(new EmailAddressValidator(), "Email", obj => obj.Email)
    .When(obj => obj.IsInternational,
          new PassportValidator(), "Passport", obj => obj.PassportNumber)
    .When(obj => !obj.IsInternational,
          new NationalIDValidator(), "NationalID", obj => obj.NationalId)
    .When(obj => obj.Age >= 18,
          new CreditCardValidator(), "Payment", obj => obj.CreditCard)
    .Build();

Complex Business Workflow

var businessPipeline = ValidationPipeline.Create()
    // Initial validation
    .AddStep(new EmailAddressValidator(), "Contact", obj => obj.Email)
    .AddStep(new PhoneNumberValidator(), "Contact", obj => obj.Phone)

    // Business type specific validation
    .When(obj => obj.BusinessType == BusinessType.Corporation,
          ValidationPipeline.Create()
              .AddStep(new TaxNumberValidator(), "Tax", obj => obj.TaxId)
              .AddStep(new CompanyNameValidator(), "Company", obj => obj.CompanyName))

    .When(obj => obj.BusinessType == BusinessType.Individual,
          ValidationPipeline.Create()
              .AddStep(new NationalIDValidator(), "Personal", obj => obj.NationalId))

    // Payment validation
    .AddStep(new IBANValidator(), "Banking", obj => obj.BankAccount)
    .Build();

Pipeline with Custom Validators

class AgeValidator : IValidator
{
    public ValidationResult Validate(object value)
    {
        var age = (int)value;
        return age >= 18 && age <= 120
            ? ValidationResult.Success("Age")
            : ValidationResult.Failure("Age", "Age must be between 18 and 120");
    }
}

var customPipeline = ValidationPipeline.Create()
    .AddStep(new NameValidator(), "Name", obj => obj.Name)
    .AddStep(new AgeValidator(), "Age", obj => obj.Age)
    .AddStep(new EmailAddressValidator(), "Email", obj => obj.Email)
    .Build();

Parallel Pipeline Execution

// For performance-critical scenarios
var parallelPipeline = ValidationPipeline.Create()
    .AddParallelStep(new EmailAddressValidator(), "Email", obj => obj.Email)
    .AddParallelStep(new PhoneNumberValidator(), "Phone", obj => obj.Phone)
    .AddParallelStep(new CreditCardValidator(), "Card", obj => obj.CreditCard)
    .Build();

// Executes validation steps in parallel for better performance
var result = await parallelPipeline.ExecuteAsync(userObject);