Skip to content

Schema Validation

LoSkroefie edited this page Jan 19, 2025 · 1 revision

Schema Validation

Overview

FLEXON's schema validation system ensures data integrity and type safety. It supports JSON Schema with additional FLEXON-specific extensions.

Basic Usage

1. Define Schema

{
  "type": "object",
  "properties": {
    "name": { "type": "string" },
    "age": { "type": "integer", "minimum": 0 },
    "email": { "type": "string", "format": "email" }
  },
  "required": ["name", "age"]
}

2. Configure Validation

var options = new FlexonOptions
{
    EnableValidation = true,
    Schema = FlexonSchema.FromString(schemaJson)
};

var serializer = new FlexonSerializer(options);

3. Use Validation

try
{
    byte[] binary = serializer.Serialize(data);
    var restored = serializer.Deserialize<Person>(binary);
}
catch (FlexonValidationException ex)
{
    foreach (var error in ex.ValidationErrors)
    {
        Console.WriteLine($"{error.Path}: {error.Message}");
    }
}

Schema Types

Primitive Types

{
  "type": "object",
  "properties": {
    "null": { "type": "null" },
    "boolean": { "type": "boolean" },
    "integer": { "type": "integer" },
    "number": { "type": "number" },
    "string": { "type": "string" }
  }
}

Arrays

{
  "type": "array",
  "items": { "type": "string" },
  "minItems": 1,
  "maxItems": 10,
  "uniqueItems": true
}

Objects

{
  "type": "object",
  "properties": {
    "id": { "type": "integer" },
    "name": { "type": "string" }
  },
  "required": ["id"],
  "additionalProperties": false
}

Validation Rules

String Validation

{
  "type": "string",
  "minLength": 3,
  "maxLength": 50,
  "pattern": "^[A-Za-z0-9]+$",
  "format": "email"
}

Number Validation

{
  "type": "number",
  "minimum": 0,
  "maximum": 100,
  "exclusiveMinimum": true,
  "multipleOf": 5
}

Object Validation

{
  "type": "object",
  "minProperties": 1,
  "maxProperties": 10,
  "dependencies": {
    "credit_card": ["billing_address"]
  }
}

Custom Formats

Define Custom Format

public class PhoneNumberFormat : IFlexonFormat
{
    public string Name => "phone";

    public bool Validate(string value)
    {
        return Regex.IsMatch(value, @"^\+?[1-9]\d{1,14}$");
    }
}

Register Format

FlexonConfiguration.RegisterFormat(new PhoneNumberFormat());

Use Custom Format

{
  "type": "string",
  "format": "phone"
}

Schema References

Internal References

{
  "definitions": {
    "address": {
      "type": "object",
      "properties": {
        "street": { "type": "string" },
        "city": { "type": "string" }
      }
    }
  },
  "properties": {
    "billing": { "$ref": "#/definitions/address" },
    "shipping": { "$ref": "#/definitions/address" }
  }
}

External References

{
  "properties": {
    "address": { "$ref": "address.schema.json" }
  }
}

Conditional Validation

If-Then-Else

{
  "if": {
    "properties": { "type": { "const": "business" } }
  },
  "then": {
    "required": ["tax_id"]
  },
  "else": {
    "required": ["ssn"]
  }
}

AllOf, AnyOf, OneOf

{
  "allOf": [
    { "required": ["name"] },
    { "required": ["email"] }
  ],
  "anyOf": [
    { "required": ["phone"] },
    { "required": ["mobile"] }
  ],
  "oneOf": [
    { "properties": { "type": { "const": "personal" } } },
    { "properties": { "type": { "const": "business" } } }
  ]
}

Error Handling

Validation Errors

public class ValidationError
{
    public string Path { get; set; }
    public string Message { get; set; }
    public string SchemaId { get; set; }
    public object InvalidValue { get; set; }
}

Custom Error Messages

{
  "type": "string",
  "pattern": "^[A-Z][a-z]+$",
  "errorMessage": {
    "pattern": "Name must start with capital letter"
  }
}

Error Collection

var errors = new List<ValidationError>();
var validator = new FlexonValidator(schema);

if (!validator.TryValidate(data, out errors))
{
    foreach (var error in errors)
    {
        Console.WriteLine($"{error.Path}: {error.Message}");
    }
}

Performance Optimization

Schema Caching

// Cache compiled schema
var cachedSchema = FlexonSchema.Compile(schemaJson);

// Reuse cached schema
var options = new FlexonOptions
{
    Schema = cachedSchema
};

Selective Validation

var options = new FlexonOptions
{
    EnableValidation = true,
    ValidationMode = ValidationMode.FirstError
};

Batch Validation

var validator = new FlexonValidator(schema);
var results = new ConcurrentDictionary<string, List<ValidationError>>();

Parallel.ForEach(items, item =>
{
    if (!validator.TryValidate(item, out var errors))
    {
        results[item.Id] = errors;
    }
});

Best Practices

  1. Schema Design

    • Keep schemas simple and focused
    • Use appropriate types
    • Document schema requirements
  2. Validation Strategy

    • Validate early
    • Fail fast
    • Collect all errors when needed
  3. Performance

    • Cache compiled schemas
    • Use appropriate validation mode
    • Consider batch validation
  4. Maintenance

    • Version your schemas
    • Document changes
    • Test validation rules

Clone this wiki locally