How to Validate Data in Python for Beginners
A beginner-friendly Python class for validating required fields, types, ranges, and allowed choices in dict payloads.
Python code
61 linesimport json
from typing import Any, Dict, List, Optional, Union
class Validator:
"""A simple validate data helper designed for beginners."""
def __init__(self, data: Union[Dict[str, Any], List[Any]]):
self.data = data
self.errors: Dict[str, str] = {}
def validate_required(self, field: str) -> "Validator":
if isinstance(self.data, dict) and field not in self.data:
self.errors[field] = "is required"
return self
def validate_type(self, field: str, expected_type: type) -> "Validator":
if isinstance(self.data, dict) and field in self.data:
if not isinstance(self.data[field], expected_type):
self.errors[field] = f"must be {expected_type.__name__}"
return self
def validate_range(self, field: str, min_value: float, max_value: float) -> "Validator":
if isinstance(self.data, dict) and field in self.data:
value = self.data[field]
if isinstance(value, (int, float)) and not (min_value <= value <= max_value):
self.errors[field] = f"must be between {min_value} and {max_value}"
return self
def validate_choices(self, field: str, choices: List[Any]) -> "Validator":
if isinstance(self.data, dict) and field in self.data:
if self.data[field] not in choices:
self.errors[field] = f"must be one of {choices}"
return self
def get_errors(self) -> Dict[str, str]:
return self.errors
def is_valid(self) -> bool:
return not self.errors
if __name__ == "__main__":
# Example usage with a sample payload
payload = {
"name": "Alice",
"age": 30,
"category": "user",
"score": 85.5,
}
validator = Validator(payload)
validator.validate_required("name")
validator.validate_type("name", str)
validator.validate_type("age", int)
validator.validate_range("age", 18, 65)
validator.validate_choices("category", ["user", "admin"])
validator.validate_range("score", 0, 100)
print(validator.get_errors())
print(validator.is_valid())
Output
{}
True
How it works
The Validator class keeps all errors in a self.errors dictionary. Each validate_* method returns self so you can chain calls on one line. Checks run only when self.data is a dict, so lists skip field validation safely. The is_valid() method simply returns whether the error dictionary is empty. This pattern keeps validation logic readable and aggregatable for beginners.
Common mistakes
- Forgetting to assign the result of chained validation methods back to the variable
- Passing a list to field-level validators, which silently does nothing because it checks `isinstance(self.data, dict)`
- Not calling `get_errors()` before checking `is_valid()` to see why it failed
Variations
- Use Pydantic's `BaseModel` for automatic validation with type coercion
- Write a standalone function that returns `(is_valid, errors)` instead of an object
Real-world use cases
- Validating request payloads before dispatching them to a gRPC service endpoint
- Checking configuration dictionaries loaded from YAML or JSON at startup
- Sanitizing form data submitted through a Flask or FastAPI route before writing to a database
Sponsored
More from API design & gRPC
- Build a Bulk Array POST Mock Server in Python medium
- Build a Mock REST API with PUT and GET in Python medium
- Convert Protobuf to JSON and Dict in Python easy
- Create a Data Helper in Python for gRPC-style APIs easy
- Format data in Python using dataclasses like gRPC messages easy
- Generate an OpenAPI Spec from Mock Routes in Python easy
Keep learning
Related tutorials and quizzes for this topic.