-
Notifications
You must be signed in to change notification settings - Fork 0
Schema Validation
LoSkroefie edited this page Jan 19, 2025
·
1 revision
FLEXON's schema validation system ensures data integrity and type safety. It supports JSON Schema with additional FLEXON-specific extensions.
{
"type": "object",
"properties": {
"name": { "type": "string" },
"age": { "type": "integer", "minimum": 0 },
"email": { "type": "string", "format": "email" }
},
"required": ["name", "age"]
}var options = new FlexonOptions
{
EnableValidation = true,
Schema = FlexonSchema.FromString(schemaJson)
};
var serializer = new FlexonSerializer(options);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}");
}
}{
"type": "object",
"properties": {
"null": { "type": "null" },
"boolean": { "type": "boolean" },
"integer": { "type": "integer" },
"number": { "type": "number" },
"string": { "type": "string" }
}
}{
"type": "array",
"items": { "type": "string" },
"minItems": 1,
"maxItems": 10,
"uniqueItems": true
}{
"type": "object",
"properties": {
"id": { "type": "integer" },
"name": { "type": "string" }
},
"required": ["id"],
"additionalProperties": false
}{
"type": "string",
"minLength": 3,
"maxLength": 50,
"pattern": "^[A-Za-z0-9]+$",
"format": "email"
}{
"type": "number",
"minimum": 0,
"maximum": 100,
"exclusiveMinimum": true,
"multipleOf": 5
}{
"type": "object",
"minProperties": 1,
"maxProperties": 10,
"dependencies": {
"credit_card": ["billing_address"]
}
}public class PhoneNumberFormat : IFlexonFormat
{
public string Name => "phone";
public bool Validate(string value)
{
return Regex.IsMatch(value, @"^\+?[1-9]\d{1,14}$");
}
}FlexonConfiguration.RegisterFormat(new PhoneNumberFormat());{
"type": "string",
"format": "phone"
}{
"definitions": {
"address": {
"type": "object",
"properties": {
"street": { "type": "string" },
"city": { "type": "string" }
}
}
},
"properties": {
"billing": { "$ref": "#/definitions/address" },
"shipping": { "$ref": "#/definitions/address" }
}
}{
"properties": {
"address": { "$ref": "address.schema.json" }
}
}{
"if": {
"properties": { "type": { "const": "business" } }
},
"then": {
"required": ["tax_id"]
},
"else": {
"required": ["ssn"]
}
}{
"allOf": [
{ "required": ["name"] },
{ "required": ["email"] }
],
"anyOf": [
{ "required": ["phone"] },
{ "required": ["mobile"] }
],
"oneOf": [
{ "properties": { "type": { "const": "personal" } } },
{ "properties": { "type": { "const": "business" } } }
]
}public class ValidationError
{
public string Path { get; set; }
public string Message { get; set; }
public string SchemaId { get; set; }
public object InvalidValue { get; set; }
}{
"type": "string",
"pattern": "^[A-Z][a-z]+$",
"errorMessage": {
"pattern": "Name must start with capital letter"
}
}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}");
}
}// Cache compiled schema
var cachedSchema = FlexonSchema.Compile(schemaJson);
// Reuse cached schema
var options = new FlexonOptions
{
Schema = cachedSchema
};var options = new FlexonOptions
{
EnableValidation = true,
ValidationMode = ValidationMode.FirstError
};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;
}
});-
Schema Design
- Keep schemas simple and focused
- Use appropriate types
- Document schema requirements
-
Validation Strategy
- Validate early
- Fail fast
- Collect all errors when needed
-
Performance
- Cache compiled schemas
- Use appropriate validation mode
- Consider batch validation
-
Maintenance
- Version your schemas
- Document changes
- Test validation rules