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.

Easy Python 3.9+ Aug 9, 2026 API design & gRPC 13 views 0 copies

Python code

61 lines
Python 3.9+
import 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

stdout
{}
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

  1. Use Pydantic's `BaseModel` for automatic validation with type coercion
  2. 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

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from API design & gRPC

Related tutorials and quizzes for this topic.