apischema: JSON (de)serialization, GraphQL, and JSON Schema

raw JSON →
0.19.0 verified Fri Apr 17 auth: no python

apischema is a Python library for JSON (de)serialization, GraphQL, and JSON schema generation, heavily leveraging Python's type hints. It is currently at version 0.19.0 and maintains an active release cadence with frequent updates and bug fixes.

pip install apischema
error TypeError: 'type' object is not subscriptable
cause Using type hints like `list[str]` or `dict[str, int]` on Python versions older than 3.9, or when `typing-extensions` is not installed on Python 3.8 where it might be needed.
fix
Ensure your Python version is 3.9 or newer. If on Python 3.8, ensure typing-extensions is installed and updated (pip install 'typing-extensions>=4.0'). Alternatively, use typing.List[str] syntax for older Python versions.
error apischema.validation.errors.ValidationError: [path]: error message
cause Input data does not conform to the type annotations or validation rules defined in the Python type. This is `apischema`'s way of reporting schema mismatches.
fix
Examine the error message to identify the field ([path]) and the expected type/format. Adjust the input data to match the Python type definition, or refine the type definition to correctly represent the expected data.
error ImportError: cannot import name 'schema_json' from 'apischema'
cause The `schema_json` function was relocated to `apischema.json_schema.schema_json_from_obj` in newer versions.
fix
Change your import statement from from apischema import schema_json to from apischema.json_schema import schema_json_from_obj.
error TypeError: 'ApischemaSettings' object is not callable
cause In older versions, `apischema.settings` was sometimes used as a callable. In newer versions (e.g., v0.18.0+), `apischema.settings` is an object, and configuration is done through `apischema.confs` or by directly setting attributes on the `apischema.settings` object.
fix
If configuring global settings, use apischema.confs.set_deserialization_coercion(True) or similar methods, or directly modify attributes like apischema.settings.deserialization.coercion = True. Do not treat apischema.settings as a function.
breaking Python 3.7 support was dropped in v0.18.2. Users on Python 3.7 or older must upgrade their Python environment to at least 3.9 (as per current PyPI `requires_python`) to use recent versions of apischema.
fix Upgrade Python to 3.9 or newer. Consider using a virtual environment.
breaking Various deprecated APIs were removed in v0.18.0. Code relying on functions or classes marked as deprecated in earlier versions will break.
fix Consult the `apischema` changelog for v0.18.0 and upgrade to the new API. Specifically look for changes around `schema_json` and `confs`.
breaking Since v0.17.0, arbitrary exceptions raised during serialization are no longer automatically converted to `ValidationError`. This change enhances security by preventing unexpected exception type conversion.
fix Update error handling logic for custom serializers. If you were catching `ValidationError` for all exceptions during serialization, you might now need to catch more specific exception types or `Exception` directly.
gotcha When defining dataclasses, using `apischema.dataclasses.dataclass` is often preferred over `dataclasses.dataclass` (from the standard library) for full feature integration.
fix Import `dataclass` from `apischema.dataclasses` to leverage advanced `apischema` features like `with_args` or special metadata handling.
pip install apischema[graphql]
pip install apischema[validation]

This quickstart demonstrates basic serialization and deserialization of a Python dataclass using `apischema`, including an example of how to handle `ValidationError`.

from dataclasses import dataclass
from apischema import serialize, deserialize
from apischema.validation.errors import ValidationError

@dataclass
class User:
    id: int
    name: str
    email: str | None = None

# Serialization
user_obj = User(id=1, name="Alice", email="alice@example.com")
serialized_data = serialize(user_obj)
print(f"Serialized: {serialized_data}")
# Expected output: {'id': 1, 'name': 'Alice', 'email': 'alice@example.com'}

# Deserialization
deserialized_obj = deserialize(User, {'id': 2, 'name': 'Bob'})
print(f"Deserialized: {deserialized_obj}")
# Expected output: User(id=2, name='Bob', email=None)

# Handling validation errors
try:
    deserialize(User, {'id': 'not-an-int', 'name': 'Charlie'})
except ValidationError as e:
    print(f"Validation Error: {e}")
# Expected output: Validation Error: [id]: must be an integer