Client collections
The published Apizr 0.4.2 release generates local Postman, Bruno and Insomnia collections from an existing Apizr REST bundle:
Python → Apizr REST bundle → client collection
First produce the bundle using repository exposure or the single-source REST workflow. Collection generation verifies retained artifacts; it does not rescan, import or execute the original project.
Install the optional clients extra with
python -m pip install "outerspace-apizr[clients]==0.4.2". Contributors can use
uv sync --extra clients in the development checkout. The extra supplies PyYAML;
the minimal core still requires only Pydantic. Apizr does not install client apps.
Export
apizr clients export --bundle .output/rest --format postman --output-dir .output/postman
apizr clients export --bundle .output/rest --format bruno --output-dir .output/bruno
apizr clients export --bundle .output/rest --format insomnia --output-dir .output/insomnia
The parent directory must already exist. The output directory must be absent or empty. Relative and absolute paths are supported; symlink traversal is refused. Output is prepared in a sibling staging directory before publication.
Use --base-url https://api.example.test to select the server explicitly. The
default is http://127.0.0.1:8000; each format uses a base_url variable.
Only HTTP(S) URLs without credentials, query strings, fragments or control
characters are accepted. --name defaults to Apizr REST API.
Each exposed capability produces one POST request with a JSON body and
Content-Type: application/json. No authentication, cookies, scripts, tests or
secrets are generated. Required arguments receive minimal deterministic values:
zero, empty string, false, null, empty containers, fixed tuple members, the first
literal or the first union member. Optional arguments are omitted so Python
defaults remain in effect. Return schemas describe the existing REST contract;
they do not introduce response enforcement or fabricated response examples.
Native formats
| Format | Output | Official validation used |
|---|---|---|
| Postman Collection 3.0.0 | .resources/definition.yaml and one *.request.yaml per capability |
Postman CLI 1.67.0 lint and local execution |
| Bruno OpenCollection 1.0.0 | opencollection.yml and one request .yml per capability |
@opencollection/schema 0.14.0 and Bruno CLI 4.2.0 |
| Insomnia v5, schema 5.1 | collection.yaml, type collection.insomnia.rest/5.0 |
Official JSON Schema and Inso CLI 13.3.0 local execution |
These are the current native formats documented by
Postman,
Bruno and
Insomnia.
The qualification tools are development-only, with exact npm versions and
integrity values in scripts/client_collection_tools/package-lock.json.
Insomnia's schema is pinned to commit
ab658aa7e419ff155511370dff3d32d53ae5ea53, SHA-256
65b37ac4118a89aa8b15e381e5bafdc7a8580f3c386b6c65b4db8ba04a86fa17.
Postman 3 local execution supports its CLI reporter, not the JSON reporter used for older collections. Qualification checks the verbose native responses and also replays the common IR against the fixture. Postman may print a login notice; local lint and execution work without an account. Bruno and Inso additionally provide machine-readable execution results. No cloud API or account is needed.
Regenerate safely
apizr clients sync --bundle .output/rest --format postman --output-dir .output/postman
sync regenerates a fully Apizr-owned local tree. It does not synchronize with a
cloud workspace or import client edits. The previous manifest, retained IR and
all owned file hashes must match. Unknown files, empty extra directories, links,
modified files, missing manifests and a different format cause refusal before
the generated tree changes.
Copy/fork a generated collection before hand-editing it. apizr clients sync
manages a generated tree; it is not a merge engine.
The replacement is staged and verified on the same filesystem. The previous
tree is renamed to a backup before the prepared tree takes its place. Caught
interruptions restore the previous tree where publication has not completed.
A crash can leave a sibling .apizr-clients-<root-name-hash>.stage, .backup
or .lock; subsequent commands refuse with client_sync_conflict. Preserve
those directories, inspect the manifest and hashes, and recover the previous
backup manually before removing stale staging/lock entries. No automatic retry
or cleanup guesses which interrupted tree to keep.
Python and portable identities
from apizr.client_collections import (
plan_client_collection,
render_client_collection,
publish_collection,
)
collection = plan_client_collection(".output/rest", base_url="http://127.0.0.1:8000")
files = render_client_collection(collection, format="bruno")
result = publish_collection(collection, format="bruno", output_dir=".output/bruno")
export_client_collection(..., sync=True) combines planning, rendering and
publication. Pure models and canonical JSON work without YAML installed.
One frozen strict apizr.client-collection/v1 model supplies every renderer.
Its SHA-256 covers canonical UTF-8 JSON with sorted keys, compact separators
and a final LF. Request ordering follows the REST manifest.
Both apizr.repository-rest/v1 and historical apizr.rest/v1 are supported.
Every manifest-declared artifact is read as a bounded regular file and checked
against its recorded digest; unrelated files are not read. OpenAPI must match
the typed endpoint contracts, including routes, methods, identities and schemas.
Repository exports retain interface and exposure-plan digests; single-source
exports retain IR and readiness digests. Manifest hashes establish retained
content identity, not independent signatures or publisher authenticity.
Each output includes apizr-client-collection.json and an
apizr.client-export/v1 manifest, apizr-client-export.json. The manifest binds
the collection digest, source REST manifest digest, format/version, explicit
options, capability IDs, generated paths and SHA-256 file hashes. It excludes
timestamps, source paths, usernames, environment and network state.
Insomnia entity IDs use the first 128 bits of SHA-256 over canonical JSON
[format, collection_digest, capability_id, role]. Request filenames use a
bounded ASCII slug and the first 64 bits of the capability ID's SHA-256, even
without a collision; this keeps names stable when new requests are added.
Case, Unicode and truncation collisions never silently discard a request.
An actual digest-name collision is refused. All files use deterministic YAML,
UTF-8, LF, stable keys and no aliases.
Limits: 512 requests, 4 MiB per input/generated file, 32 MiB total input/export, 2,048 files, 256 UTF-8 bytes per name/identity, 8 KiB per description, 128 bytes per generated path component and 512 per relative path. Oversize inputs are refused without truncation.
CLI stdout is canonical JSON: apizr.client-export-result/v1 on success, or a
fixed diagnostic on refusal. Exit codes are 0 for success, 1 for changed input
or output ownership conflicts, 2 for invalid/operational input or a missing
clients extra, and 130 for cancellation. Diagnostics include
rest_bundle_invalid, rest_bundle_changed, client_format_unsupported,
client_collection_too_large, client_name_invalid, client_base_url_invalid,
client_path_collision, client_output_not_empty, client_export_invalid,
client_export_modified, client_sync_conflict and clients_extra_required.