Length Validation — Complete Guide
In this tutorial, you'll learn about Length Validation. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.
Length validation checks that strings and collections have sizes within expected boundaries, preventing too-short or too-long inputs.
What You'll Learn
By the end of this lesson, you will validate string lengths, array lengths, byte sizes, and handle Unicode character length vs byte length differences.
Why It Matters
Without length limits, an attacker can send a 10MB JSON string and crash your server. Length validation prevents resource exhaustion and data truncation.
Real-World Use
Twitter's 280-character limit is a length validation. Without it, tweets could fill databases. The same principle applies to all user-generated content.
Length Validator
# length_validator.py
from typing import Any, Dict, List, Optional
class LengthValidator:
@staticmethod
def string(value: Any, min_len: Optional[int] = None,
max_len: Optional[int] = None) -> Optional[str]:
if not isinstance(value, str):
return "Value must be a string"
stripped = value.strip()
if min_len is not None and len(stripped) < min_len:
return f"Minimum {min_len} character{'s' if min_len != 1 else ''}"
if max_len is not None and len(value) > max_len:
return f"Maximum {max_len} character{'s' if max_len != 1 else ''}"
return None
@staticmethod
def array(value: Any, min_items: Optional[int] = None,
max_items: Optional[int] = None) -> Optional[str]:
if not isinstance(value, (list, tuple)):
return "Value must be an array"
if min_items is not None and len(value) < min_items:
return f"At least {min_items} item{'s' if min_items != 1 else ''} required"
if max_items is not None and len(value) > max_items:
return f"At most {max_items} item{'s' if max_items != 1 else ''} allowed"
return None
@staticmethod
def byte_length(value: str, encoding: str = "utf-8",
max_bytes: Optional[int] = None) -> Optional[str]:
if not isinstance(value, str):
return "Value must be a string"
if max_bytes is not None:
byte_len = len(value.encode(encoding))
if byte_len > max_bytes:
return f"Maximum {max_bytes} bytes (current: {byte_len})"
return None
lv = LengthValidator()
print(f"String 'Hi' (2-10): {lv.string('Hi', 2, 10)}")
print(f"String 'A' (min 2): {lv.string('A', 2)}")
print(f"String long (max 5): {lv.string('Hello World', max_len=5)}")
print(f"Array [1,2] (1-3): {lv.array([1, 2], 1, 3)}")
print(f"Array [] (min 1): {lv.array([], min_items=1)}")
print(f"Bytes 'Hello' (max 10): {lv.byte_length('Hello', max_bytes=10)}")
print(f"Bytes 'Hello!' (max 5): {lv.byte_length('Hello!', max_bytes=5)}")
Expected output:
String 'Hi' (2-10): None
String 'A' (min 2): Minimum 2 characters
String long (max 5): Maximum 5 characters
Array [1,2] (1-3): None
Array [] (min 1): At least 1 item required
Bytes 'Hello' (max 10): None
Bytes 'Hello!' (max 5): Maximum 5 bytes (current: 6)
Unicode Length Handling
# unicode_length.py
from typing import Any, Optional
class UnicodeLengthValidator:
@staticmethod
def char_length(value: str) -> int:
return len(value)
@staticmethod
def byte_length(value: str, encoding: str = "utf-8") -> int:
return len(value.encode(encoding))
@staticmethod
def grapheme_clusters(value: str) -> int:
import unicodedata
count = 0
for c in value:
if unicodedata.combining(c) == 0:
count += 1
else:
count += 1
return count
@staticmethod
def validate(value: str, max_chars: Optional[int] = None,
max_bytes: Optional[int] = None) -> list:
errors = []
if max_chars and len(value) > max_chars:
errors.append(f"Max {max_chars} characters ({len(value)} current)")
if max_bytes:
b = len(value.encode("utf-8"))
if b > max_bytes:
errors.append(f"Max {max_bytes} bytes ({b} current)")
return errors
ulv = UnicodeLengthValidator()
tests = [
"Hello",
"cafe\u0301", # cafe + combining accent (5 chars)
"\U0001f600", # emoji (1 char, 4 bytes)
]
for t in tests:
chars = ulv.char_length(t)
bytes_l = ulv.byte_length(t)
print(f" {t!r:20s} chars={chars} bytes={bytes_l}")
Expected output:
'Hello' chars=5 bytes=5
'cafe\u0301' chars=5 bytes=6
'\U0001f600' chars=1 bytes=4
Schema Length Rules
# schema_length.py
from typing import Any, Dict, List, Optional
class SchemaLengthValidator:
def __init__(self):
self.rules: Dict[str, Dict] = {}
def string_field(self, name: str, min_len: int = 0, max_len: Optional[int] = None):
self.rules[name] = {"type": "string", "min": min_len, "max": max_len}
def array_field(self, name: str, min_items: int = 0, max_items: Optional[int] = None):
self.rules[name] = {"type": "array", "min": min_items, "max": max_items}
def validate(self, data: Dict) -> List[Dict]:
errors = []
for field, rule in self.rules.items():
value = data.get(field)
if value is None:
continue
if rule["type"] == "string":
if not isinstance(value, str):
errors.append({"field": field, "code": "not_string"})
else:
if rule["min"] and len(value) < rule["min"]:
errors.append({"field": field, "code": "min_length", "min": rule["min"]})
if rule["max"] and len(value) > rule["max"]:
errors.append({"field": field, "code": "max_length", "max": rule["max"]})
elif rule["type"] == "array":
if not isinstance(value, (list, tuple)):
errors.append({"field": field, "code": "not_array"})
else:
if rule["min"] and len(value) < rule["min"]:
errors.append({"field": field, "code": "min_items", "min": rule["min"]})
if rule["max"] and len(value) > rule["max"]:
errors.append({"field": field, "code": "max_items", "max": rule["max"]})
return errors
sv = SchemaLengthValidator()
sv.string_field("username", min_len=3, max_len=30)
sv.array_field("tags", min_items=1, max_items=5)
print(sv.validate({"username": "ab", "tags": []}))
print(sv.validate({"username": "alice", "tags": ["api"]}))
Expected output:
[{'field': 'username', 'code': 'min_length', 'min': 3}, {'field': 'tags', 'code': 'min_items', 'min': 1}]
[]
Common Mistakes
1. Not Trimming Before Length Check
" Hi " is 8 characters but only 2 meaningful. Trim first, then check length.
2. Confusing Character and Byte Length
Unicode characters can be 1-4 bytes. Use character count for UX, byte count for storage.
3. Same Length for All Fields
Username (3-30), bio (0-500), title (1-200) — each field needs its own length.
4. No Upper Limit
No max length allows DoS attacks with massive inputs. Always set a maximum.
5. Ignoring Array Length
Arrays without item limits can receive millions of items. Always set max_items.
Practice Questions
1. What is the difference between character and byte length?
Character length counts visible characters. Byte length counts storage size. Emojis are 1 char but 4 bytes.
2. Why trim before length check?
Leading/trailing whitespace inflates the count. Trim to get meaningful content length.
**3. What is a safe maximum string length for API inputs?"
Depends on the field. Usernames: 30. Emails: 254. Bios: 500. Always research reasonable limits.
4. Why validate array lengths?
Prevent DoS: a 100,000-item array could crash your server. Set reasonable max_items.
Challenge
Build a length validation system for a blog post: title (5-200 chars), slug (3-100 chars), content (100-50000 chars), tags (1-10 items), meta_description (0-320 chars).
FAQ
Mini Project: Length Manager
# length_mgr.py
from typing import Any, Dict, List, Optional
def check_length(value: Any, field: str, min_v: int = 0, max_v: Optional[int] = None) -> Optional[str]:
if min_v and len(value) < min_v:
return f"{field}: min {min_v}"
if max_v and len(value) > max_v:
return f"{field}: max {max_v}"
return None
print(check_length("ab", "name", 3, 50))
print(check_length("Alice", "name", 3, 50))
Expected output:
name: min 3
None
What's Next
You understand length validation. Next, learn regex validation, then cross-field validation.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro