Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Validation

TODO: This section is under development. Basic schema validation patterns are outlined below.

Overview

Schema validation ensures that SCIM resources conform to their defined schemas before being stored or processed. This includes validating data types, required fields, constraints, and custom business rules.

Built-in Validation

Core Schema Validation

#![allow(unused)]
fn main() {
use scim_server::{Schema, ValidationError, ValidationResult};
use serde_json::Value;

pub struct SchemaValidator {
    schemas: HashMap<String, Schema>,
}

impl SchemaValidator {
    pub fn validate_resource(
        &self,
        resource: &Value,
        resource_type: &str,
    ) -> ValidationResult {
        let schemas = self.extract_schemas(resource)?;
        
        for schema_id in schemas {
            let schema = self.schemas.get(&schema_id)
                .ok_or_else(|| ValidationError::UnknownSchema(schema_id.clone()))?;
            
            self.validate_against_schema(resource, schema)?;
        }
        
        Ok(())
    }
    
    fn validate_against_schema(
        &self,
        resource: &Value,
        schema: &Schema,
    ) -> ValidationResult {
        for attribute in schema.attributes() {
            self.validate_attribute(resource, attribute)?;
        }
        Ok(())
    }
}
}

Attribute Validation

#![allow(unused)]
fn main() {
use scim_server::schema::{Attribute, AttributeType, Mutability};

impl SchemaValidator {
    fn validate_attribute(
        &self,
        resource: &Value,
        attribute: &Attribute,
    ) -> ValidationResult {
        let value = resource.get(attribute.name());
        
        // Check required attributes
        if attribute.required() && value.is_none() {
            return Err(ValidationError::MissingRequired(attribute.name().to_string()));
        }
        
        if let Some(value) = value {
            // Type validation
            self.validate_type(value, attribute.type_())?;
            
            // Constraints validation
            if let Some(canonical_values) = attribute.canonical_values() {
                self.validate_canonical_values(value, canonical_values)?;
            }
            
            // Custom validation rules
            self.validate_custom_rules(value, attribute)?;
        }
        
        Ok(())
    }
    
    fn validate_type(&self, value: &Value, expected_type: AttributeType) -> ValidationResult {
        match expected_type {
            AttributeType::String => {
                if !value.is_string() {
                    return Err(ValidationError::TypeMismatch {
                        expected: "string".to_string(),
                        actual: value.clone(),
                    });
                }
            },
            AttributeType::Boolean => {
                if !value.is_boolean() {
                    return Err(ValidationError::TypeMismatch {
                        expected: "boolean".to_string(),
                        actual: value.clone(),
                    });
                }
            },
            AttributeType::Integer => {
                if !value.is_i64() {
                    return Err(ValidationError::TypeMismatch {
                        expected: "integer".to_string(),
                        actual: value.clone(),
                    });
                }
            },
            // TODO: Add other type validations
        }
        Ok(())
    }
}
}

Custom Validation Rules

Business Logic Validation

TODO: Implement custom business rule validation patterns.

Cross-Field Validation

TODO: Add examples for validating relationships between fields.

Validation Errors

#![allow(unused)]
fn main() {
#[derive(Debug)]
pub enum ValidationError {
    MissingRequired(String),
    TypeMismatch {
        expected: String,
        actual: Value,
    },
    InvalidValue {
        field: String,
        value: Value,
        reason: String,
    },
    UnknownSchema(String),
    CustomRule {
        rule: String,
        message: String,
    },
}

impl std::fmt::Display for ValidationError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            ValidationError::MissingRequired(field) => {
                write!(f, "Missing required field: {}", field)
            },
            ValidationError::TypeMismatch { expected, actual } => {
                write!(f, "Type mismatch: expected {}, got {:?}", expected, actual)
            },
            ValidationError::InvalidValue { field, value, reason } => {
                write!(f, "Invalid value for {}: {:?} ({})", field, value, reason)
            },
            ValidationError::UnknownSchema(schema) => {
                write!(f, "Unknown schema: {}", schema)
            },
            ValidationError::CustomRule { rule, message } => {
                write!(f, "Custom rule '{}' failed: {}", rule, message)
            },
        }
    }
}
}

Integration with Providers

#![allow(unused)]
fn main() {
impl ResourceProvider for ValidatedProvider {
    async fn create_resource(
        &self,
        resource_type: &str,
        data: Value,
        context: &RequestContext,
    ) -> Result<ScimResource, ProviderError> {
        // Validate before creating
        self.validator.validate_resource(&data, resource_type)
            .map_err(|e| ProviderError::ValidationFailed(e))?;
        
        // Proceed with creation
        self.inner.create_resource(resource_type, data, context).await
    }
}
}

Testing Validation

#![allow(unused)]
fn main() {
#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn test_required_field_validation() {
        // TODO: Test required field validation
    }
    
    #[test]
    fn test_type_validation() {
        // TODO: Test type validation
    }
    
    #[test]
    fn test_custom_rules() {
        // TODO: Test custom validation rules
    }
}
}

TODO: Add more comprehensive validation patterns and examples.