Configuration: JSON loader¶
Container.from_json(path) is the JSON counterpart of
from_toml. It uses the standard-library
json module (no extra runtime dependency) and shares the
same validation pipeline, the same ContainerConfig schema,
and the same importlib-based qualified-name resolution.
{
"modules": ["my_app.modules.CacheModule"],
"bindings": [
{
"token": "my_app.services.Clock",
"factory": "my_app.factories.make_clock",
"lifecycle": "singleton"
},
{
"token": "my_app.services.Session",
"factory": "my_app.factories.make_session_async",
"lifecycle": "scoped",
"async_factory": true
},
{
"token": "my_app.services.App",
"factory": "my_app.factories.make_app",
"lifecycle": "transient",
"auto_inject": true
}
]
}
Decoding errors¶
A malformed JSON file surfaces as ConfigurationError with the
decoder's message attached. Consumers can catch a single
exception type for every kind of declarative failure, parser
included:
try:
Container.from_json("broken.json")
except ConfigurationError as exc:
log.error("config rejected: %s", exc)
The underlying json.JSONDecodeError is wrapped, not exposed.
Why JSON?¶
JSON is universal: every editor, every CI pipeline, every
serialization layer speaks it. It is the natural fit when the
container's wiring is produced by another tool (a code
generator, an orchestrator, a UI), and it lives well alongside
TOML (config-toml.md) for human-authored cases.
For human-authored configuration on developer machines, prefer TOML; for machine-generated or interchange-formatted configuration, prefer JSON.
Schema parity¶
The JSON schema is identical to the TOML schema; only the
serialization format differs. Switching between the two is a
file conversion away. The TOML examples in
config-toml.md translate directly: each
[[bindings]] table becomes one object in the JSON bindings
array, modules = [...] becomes a "modules": [...] array,
and the optional flags carry the same names and types.