JSON Encoding and Validation in Python: Msgspec vs. Pydantic
To JSON-encode a Python object using msgspec, you use the msgspec.json.encode() function. This function takes a Python object and returns a bytes object containing the JSON representation. msgspec is known for its high performance and correctness in handling data serialization.
Here's a simple guide with examples.
Encoding a Basic Python Objectโ
You can encode standard Python types like dictionaries, lists, integers, and strings.
import msgspec
data = {
"name": "Alice",
"age": 30,
"is_active": True,
"hobbies": ["reading", "hiking"]
}
# Encode the dictionary to JSON bytes
json_bytes = msgspec.json.encode(data)
# The result is a bytes object
print(json_bytes)
# Output: b'{"name":"Alice","age":30,"is_active":true,"hobbies":["reading","hiking"]}'
# You can decode it to a string for printing if needed
print(json_bytes.decode())
# Output: {"name":"Alice","age":30,"is_active":true,"hobbies":["reading","hiking"]}
Encoding a msgspec.Structโ
The true power of msgspec lies in its ability to efficiently encode typed data structures, which it calls Structs. This is significantly faster than standard json library when you have a predefined schema.
import msgspec
class User(msgspec.Struct):
name: str
age: int
is_active: bool = True # Default value
hobbies: list[str] = msgspec.field(default_factory=list)
# Create an instance of the struct
user = User(name="Bob", age=25)
# Encode the struct instance
user_json_bytes = msgspec.json.encode(user)
print(user_json_bytes.decode())
# Output: {"name":"Bob","age":25,"is_active":true,"hobbies":[]}
Handling Custom Encodersโ
If your object contains types that msgspec doesn't know how to encode by default (e.g., a datetime object), you can provide a custom encoder function using the enc_hook parameter.
import msgspec
from datetime import datetime
class Event(msgspec.Struct):
name: str
start_time: datetime
# Create an object with a datetime field
event = Event(name="Meeting", start_time=datetime(2025, 8, 23, 10, 0, 0))
def my_encoder(obj):
if isinstance(obj, datetime):
return obj.isoformat()
raise TypeError(f"Cannot encode {type(obj)}")
# Encode the object using the custom encoder hook
event_json_bytes = msgspec.json.encode(event, enc_hook=my_encoder)
print(event_json_bytes.decode())
# Output: {"name":"Meeting","start_time":"2025-08-23T10:00:00"}
The enc_hook function is called for any value that cannot be encoded by msgspec's built-in encoder. If your hook successfully returns an encodable value, msgspec will use that. If not, it will raise a TypeError.
Annotating JSON Schema Properties with Msgspecโ
msgspec allows customizing property names and schema annotations for JSON using msgspec.Meta and field renamed configurations.
import msgspec
from typing import Annotated
class User(msgspec.Struct, rename="lower"):
user_id: Annotated[int, msgspec.Meta(gt=0, description="Unique user ID")]
user_name: str
encoded = msgspec.json.encode(User(user_id=1, user_name="Alice"))
print(encoded.decode())
# Output: {"user_id":1,"user_name":"Alice"}
Pydantic for JSON Validationโ
When rich ecosystem features or loose validation are preferred, Pydantic offers built-in JSON parsing and validation methods:
from pydantic import BaseModel, Field
class UserPayload(BaseModel):
id: int = Field(gt=0)
name: str
# Validate raw JSON string
user = UserPayload.model_validate_json('{"id": 42, "name": "Bob"}')
print(user.name) # Bob
Use msgspec for maximum speed in JSON encoding/decoding loops, and Pydantic for OpenAPI generation and FastAPI integrations.
