Required Field Validation — Complete Guide
In this tutorial, you'll learn about Required Field Validation. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.
Required field validation ensures that mandatory fields are present and non-empty before processing a request.
What You'll Learn
By the end of this lesson, you will implement required field checks, handle edge cases like empty strings and whitespace, and implement conditional required fields.
Why It Matters
Missing required fields are the most common validation error. Proper required field handling prevents partial data, null reference errors, and inconsistent state.
Real-World Use
A payment API requires amount, currency, and source fields. Missing any one causes a 400 error before any charge is attempted.
Required Field Checker
# required_checker.py
from typing import Any, Dict, List, Optional
class RequiredChecker:
@staticmethod
def check(value: Any, field: str) -> Optional[str]:
if value is None:
return f"{field}: is required"
if isinstance(value, str):
if value.strip() == "":
return f"{field}: cannot be empty"
if value.strip() == "null" or value.strip() == "undefined":
return f"{field}: invalid value"
if isinstance(value, list) and len(value) == 0:
return f"{field}: at least one item required"
if isinstance(value, dict) and len(value) == 0:
return f"{field}: cannot be empty object"
return None
@staticmethod
def check_all(data: Dict, required_fields: List[str]) -> List[Dict]:
errors = []
for field in required_fields:
error = RequiredChecker.check(data.get(field), field)
if error:
errors.append({"field": field, "message": error})
return errors
checker = RequiredChecker()
tests = [
("name", None),
("name", ""),
("name", " "),
("name", "Alice"),
("tags", []),
("tags", ["api"]),
("meta", {}),
]
for field, value in tests:
err = checker.check(value, field)
print(f" field={field:8s} value={str(value):12s} -> {'VALID' if not err else err}")
Expected output:
field=name value=None -> name: is required
field=name value= -> name: cannot be empty
field=name value=' ' -> name: cannot be empty
field=name value='Alice' -> VALID
field=tags value=[] -> tags: at least one item required
field=tags value=['api'] -> VALID
field=meta value={} -> meta: cannot be empty object
Conditional Required Fields
# conditional_required.py
from typing import Any, Dict, List, Optional
class ConditionalRequired:
@staticmethod
def if_present(field: str, depends_on: str, data: Dict) -> Optional[str]:
if depends_on in data and data[depends_on] is not None:
if field not in data or data[field] is None:
return f"{field}: required when {depends_on} is provided"
return None
@staticmethod
def if_value(field: str, condition_field: str, condition_value: Any,
data: Dict) -> Optional[str]:
if data.get(condition_field) == condition_value:
if field not in data or data[field] is None:
return f"{field}: required when {condition_field} is {condition_value}"
return None
@staticmethod
def one_of(group: List[str], data: Dict) -> Optional[str]:
provided = [f for f in group if f in data and data[f] is not None]
if len(provided) == 0:
return f"At least one of {group} is required"
if len(provided) > 1:
return f"Only one of {group} is allowed, got {provided}"
return None
cr = ConditionalRequired()
data = {"payment_method": "card"}
print(f"card_number required? {cr.if_value('card_number', 'payment_method', 'card', data)}")
data2 = {"payment_method": "card"}
print(f"One of (card, bank) required? {cr.one_of(['card_number', 'bank_account'], data2)}")
data3 = {"payment_method": "card", "card_number": "4111"}
print(f"Card number with card: {cr.if_value('card_number', 'payment_method', 'card', data3)}")
Expected output:
card_number required? card_number: required when payment_method is card
One of (card, bank) required? At least one of ['card_number', 'bank_account'] is required
Card number with card: None
Required Field Aggregator
# required_aggregator.py
from typing import Any, Dict, List
class RequiredFieldAggregator:
def __init__(self):
self.fields: List[str] = []
self.conditional_rules: List[callable] = []
def requires(self, *fields: str):
self.fields.extend(fields)
def requires_if(self, field: str, condition_fn: callable):
self.conditional_rules.append((field, condition_fn))
def validate(self, data: Dict) -> List[Dict]:
errors = []
for field in self.fields:
value = data.get(field)
if value is None or (isinstance(value, str) and value.strip() == ""):
errors.append({"field": field, "code": "required"})
for field, condition in self.conditional_rules:
if condition(data) and (data.get(field) is None):
errors.append({"field": field, "code": "required_conditional"})
return errors
agg = RequiredFieldAggregator()
agg.requires("email", "password")
agg.requires_if("card_number", lambda d: d.get("payment") == "card")
print(agg.validate({"payment": "card"}))
print(agg.validate({"email": "a@x.com", "password": "123", "payment": "card", "card_number": "4111"}))
Expected output:
[{'field': 'email', 'code': 'required'}, {'field': 'password', 'code': 'required'}, {'field': 'card_number', 'code': 'required_conditional'}]
[]
Common Mistakes
1. Not Checking Empty Strings
Required fields with value "" pass is not None check. Always check for empty strings.
2. Not Trimming Before Check
A field with value " " is not empty but is effectively empty. Trim before checking.
3. Conditional Logic Too Complex
Deeply nested conditional requirements confuse clients. Flatten if possible.
4. Inconsistent Required Rules
Same field required in one endpoint, optional in another. Document endpoint-specific rules.
5. Required Read-Only Fields
Marking fields as required that the server calculates (like created_at) confuses clients.
Practice Questions
1. What values should a required field reject?
None, empty string, whitespace-only strings. Empty arrays and objects may also be rejected.
2. What is a conditional required field?
A field that is required only when another field has a specific value.
3. How do you implement one-of required groups?
Check that exactly one field from a group is present. Return error if zero or more than one.
4. Should you trim before required check?
Yes. A whitespace-only string is effectively empty. Trim and then check.
Challenge
Build a conditional required field system for a shipping form: address is required if shipping method is physical, digital_license is required if method is digital.
FAQ
Mini Project: Required Field Manager
# required_mgr.py
from typing import Any, Dict, List
class RequiredManager:
def __init__(self):
self.required = set()
def add(self, field: str):
self.required.add(field)
def check(self, data: Dict) -> List[str]:
missing = []
for field in self.required:
if field not in data or data[field] is None or data[field] == "":
missing.append(f"{field} required")
return missing
mgr = RequiredManager()
mgr.add("username")
mgr.add("email")
print(mgr.check({"username": "alice"}))
print(mgr.check({"username": "alice", "email": "a@x.com"}))
Expected output:
['email required']
[]
What's Next
You understand required fields. Next, learn type checking, then format validation.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro