Validation Strategy
Services implement multi-layered validation to ensure data integrity:- Required Field Validation - Check for presence of mandatory fields
- Data Normalization - Trim whitespace and standardize format
- Uniqueness Validation - Prevent duplicate entries
- Integrity Constraints - Database-level constraint handling
Required Field Validation
All create and update operations validate required fields before database interaction.Empty Name Check
app/catalogs/colors/services.py
- Missing key in dictionary (
not name) - Empty string (
"") - Whitespace-only string (
" ","\t","\n")
Multi-Field Validation
Some services require multiple fields:app/catalogs/unit_of_measures/services.py
Data Normalization
Before validation and persistence, data is normalized to ensure consistency.Whitespace Trimming
app/catalogs/roles/services.py
- Prevents accidental spaces in names
- Ensures consistent database entries
- Improves search and comparison operations
Example Normalization Flow
Uniqueness Validation
Services prevent duplicate entries using database queries before insert/update operations.Case-Insensitive Uniqueness (Colors)
app/catalogs/colors/services.py
"Red"and"red"are considered duplicates"Blue"and"BLUE"are considered duplicates- Prevents case variations of the same name
Case-Insensitive Uniqueness (Unit of Measures)
app/catalogs/unit_of_measures/services.py
func.lower() on both sides ensures database-level case-insensitive comparison.
Case-Sensitive Uniqueness (Wood Types)
app/catalogs/wood_types/services.py
Update Uniqueness Validation
When updating, exclude the current record from uniqueness checks:app/catalogs/colors/services.py
- Allows updating without changing the name
- Only checks for conflicts with OTHER records
- Prevents false positive when name remains unchanged
Alternative Update Pattern
app/catalogs/roles/services.py
IntegrityError Handling
Database-level constraints provide a final safety layer.Transaction Rollback on Constraint Violation
app/catalogs/colors/services.py
- Handles race conditions between uniqueness check and commit
- Catches database-level UNIQUE constraint violations
- Ensures database consistency even under concurrent requests
- Provides user-friendly error messages
Update with IntegrityError
app/catalogs/unit_of_measures/services.py
Complete Validation Flow
Here’s the full validation sequence for creating a record:app/catalogs/colors/services.py
Validation Patterns Summary
| Validation Type | Example | Purpose |
|---|---|---|
| Empty check | if not name or not name.strip() | Reject missing/empty values |
| Whitespace trim | name = name.strip() | Normalize input |
| Case-insensitive unique | func.lower(Color.name) == name.lower() | Prevent case duplicates |
| Exclude self in update | Color.id_color != id_color | Allow name unchanged |
| IntegrityError catch | except IntegrityError: rollback() | Handle race conditions |
Common Validation Errors
ValidationError (400)
Raised when required fields are missing or invalid:ConflictError (409)
Raised when uniqueness constraints are violated:Best Practices
- Validate Early: Check required fields before database queries
- Normalize First: Strip whitespace before validation and storage
- Use Case-Insensitive Comparison: Apply
func.lower()for user-facing names - Always Catch IntegrityError: Protect against race conditions
- Always Rollback: Call
db.session.rollback()before re-raising - Provide Context: Include the attempted value in error messages
- Exclude Self in Updates: Prevent false conflicts when name unchanged