Documentation navigationNavigare documentație
ExamplesExemple · API 0.8.0
docx-template
Each example is a fixture directory validated at build time against the released contracts: a JSON contract, a declarative transform, a template, a curl sequence and the expected output. Guides embed these files verbatim so documentation cannot drift from validated fixtures.Fiecare exemplu este un director de fixture-uri validat la build față de contractele publicate: un contract JSON, o transformare declarativă, un șablon, o secvență curl și rezultatul așteptat. Ghidurile includ aceste fișiere textual, astfel încât documentația nu poate devia de fixture-urile validate.
Files in this fixtureFișierele acestui fixture
docx-template/authoring-limits.json · 1756 bytes · sha256 48f364a8a63db31e…{
"media_type": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"compressed_bytes": 10485760,
"expanded_bytes": 67108864,
"archive_entries": 2048,
"bindings": 256,
"binding_bytes": 256,
"binding_syntax": "{{/rfc6901/json-pointer}}",
"binding_rules": [
"A binding is {{ followed by a non-root RFC 6901 JSON Pointer and }}; the pointer must start with / and may only use ~0 and ~1 escapes.",
"Bindings may be split across runs inside one paragraph (Word does this while you type) but never across paragraphs or table cells.",
"Bindings are collected from the main document and from every header, footer, footnotes and endnotes part it references; they are returned sorted and unique.",
"At release time every binding must resolve to a string, number or boolean in the transformed output; null, missing, objects and arrays are rejected."
],
"text_parts": ["word/document.xml", "word/header*.xml", "word/footer*.xml", "word/footnotes.xml", "word/endnotes.xml"],
"allowed_parts": ["[Content_Types].xml", "*.rels", "word/styles*.xml", "word/numbering.xml", "word/settings.xml", "word/webSettings.xml", "word/fontTable.xml", "word/comments*.xml", "word/people.xml", "word/theme/theme*.xml", "docProps/*.xml", "word/media/* (png, jpg, jpeg, gif, bmp, tif, tiff, emf, wmf, webp)"],
"rejected": ["macros and vbaProject parts", "ActiveX controls", "OLE embeddings and .bin parts", "AltChunk imports", "encrypted or non-deflate archive entries", "duplicate or path-traversing entry names", "XML with DOCTYPE or external entities"],
"validation_codes": ["compressed_limit", "expanded_limit", "entry_limit", "unsafe_archive", "invalid_package", "unsafe_content", "invalid_binding", "binding_limit"]
}
docx-template/create-template.request.json · 185 bytes · sha256 1d4a5c032c14fb40…{
"slug": "person-welcome-letter",
"name": "Person welcome letter",
"description": "Docs example: DOCX template with four bindings resolved from the person welcome projection."
}
docx-template/curl.sh · 2613 bytes · sha256 ae4428454bb2ac7c…#!/bin/sh
# Docula example: DOCX template authoring.
# login -> upload template.docx (createTemplate, multipart) -> read the extracted bindings -> preview against a transform version and case.
# Requires curl and jq. Environment: DOCULA_API, DOCULA_ORIGIN (defaults to DOCULA_API), DOCULA_USERNAME, DOCULA_PASSWORD,
# DOCULA_TRANSFORM_VERSION_ID (published; see the declarative-transform example) and DOCULA_CASE_ID (valid or boundary case).
set -eu
API=${DOCULA_API:?set DOCULA_API to the API origin, for example http://127.0.0.1:18081}
ORIGIN=${DOCULA_ORIGIN:-$API}
HERE=$(cd "$(dirname "$0")" && pwd)
JAR=$(mktemp)
trap 'rm -f "$JAR" "$JAR.body"' EXIT
CSRF=$(jq -n --arg u "${DOCULA_USERNAME:?}" --arg p "${DOCULA_PASSWORD:?}" '{username: $u, password: $p}' |
curl --fail --silent --show-error -c "$JAR" -H "Origin: $ORIGIN" -H 'Content-Type: application/json' \
--data-binary @- "$API/api/v1/auth/login" | jq -r '.csrf_token')
# 1. Upload (createTemplate, multipart/form-data, at most 10 MiB). The API validates the package, rejects active content,
# extracts the {{/pointer}} bindings and stores version 1 with its SHA-256.
TEMPLATE=$(curl --fail --silent --show-error -b "$JAR" -X POST -H "Origin: $ORIGIN" -H "X-CSRF-Token: $CSRF" \
-F 'name=Person welcome letter' -F 'description=Docs example: DOCX template with four bindings.' \
-F "file=@$HERE/template.docx;type=application/vnd.openxmlformats-officedocument.wordprocessingml.document" \
"$API/api/v1/templates")
TEMPLATE_ID=$(printf '%s' "$TEMPLATE" | jq -r '.template.id')
VERSION_NUMBER=$(printf '%s' "$TEMPLATE" | jq -r '.template.versions[0].number')
# 2. The stored manifest must match template.manifest.json (same bytes, same bindings).
printf '%s' "$TEMPLATE" | jq '.template.versions[0] | {number, byte_size, content_hash, bindings}'
[ "$(printf '%s' "$TEMPLATE" | jq -r '.template.versions[0].content_hash')" = "$(jq -r '.content_hash' "$HERE/template.manifest.json")" ] ||
{ echo "uploaded content_hash differs from template.manifest.json" >&2; exit 1; }
# 3. Resolve every binding against a published transform version and a case (previewTemplateVersion).
jq --arg t "${DOCULA_TRANSFORM_VERSION_ID:?}" --arg k "${DOCULA_CASE_ID:?}" '.transform_version_id = $t | .case_id = $k' \
"$HERE/preview-template.request.json" > "$JAR.body"
curl --fail --silent --show-error -b "$JAR" -X POST -H "Origin: $ORIGIN" -H "X-CSRF-Token: $CSRF" \
-H 'Content-Type: application/json' --data-binary @"$JAR.body" \
"$API/api/v1/templates/$TEMPLATE_ID/versions/$VERSION_NUMBER/preview" | jq '{bindings, bindings_hash, preview_hash}'
docx-template/fixture.json · 2173 bytes · sha256 1a69a7a0a0026e77…{
"schema": "docula.example-fixture/v1",
"slug": "docx-template",
"guide": "/developers/guides/templates",
"title": "DOCX template authoring",
"summary": "A small real .docx with four {{/pointer}} bindings in the body, a table and a header, the manifest the API stores for it (bytes, SHA-256, sorted bindings), the authoring limits enforced by the upload validator, and the curl sequence that uploads it and previews the bindings.",
"operations": ["login", "createTemplate", "previewTemplateVersion"],
"related": ["declarative-transform", "release-immutability"],
"files": [
{ "path": "template.docx", "purpose": "Minimal WordprocessingML package generated by the Go test: document, header and relationships, stored entries, no active content.", "validate": { "kind": "docx", "manifestFile": "template.manifest.json" }, "authority": "internal/templates/examples_fixture_test.go" },
{ "path": "template.manifest.json", "purpose": "What ValidateDOCX extracts from template.docx: byte size, SHA-256 and the sorted unique bindings.", "validate": { "kind": "docx-manifest", "docxFile": "template.docx" }, "authority": "internal/templates/examples_fixture_test.go" },
{ "path": "authoring-limits.json", "purpose": "Upload and binding limits from internal/templates/docx.go plus the package rules the validator enforces.", "validate": { "kind": "json", "expect": { "/bindings": 256, "/compressed_bytes": 10485760 } }, "authority": "internal/templates/examples_fixture_test.go" },
{ "path": "create-template.request.json", "purpose": "createTemplate JSON body for a canonical template family (the multipart form in curl.sh is the immediate upload).", "validate": { "kind": "openapi", "schema": "#/components/schemas/CanonicalTemplateCreateRequest" } },
{ "path": "preview-template.request.json", "purpose": "previewTemplateVersion body: the transform version and case used to resolve the bindings.", "validate": { "kind": "openapi", "schema": "#/components/schemas/TemplatePreviewRequest" } },
{ "path": "curl.sh", "purpose": "Upload the template, compare the stored manifest, preview the bindings.", "validate": { "kind": "shell" } }
]
}
docx-template/preview-template.request.json · 122 bytes · sha256 020b4863e18b7086…{
"transform_version_id": "22222222-2222-4222-8222-000000000001",
"case_id": "44444444-4444-4444-8444-000000000001"
}
docx-template/template.docx · 3539 bytes · sha256 302f1d78302d094d…Binary fixture; only its size and SHA-256 are shown.Fixture binar; sunt afișate doar dimensiunea și SHA-256. 302f1d78302d094df37225b1b9e0e463a5516937da347874d24373187f00ef1e
docx-template/template.manifest.json · 302 bytes · sha256 4b7d79b8dcab1ef2…{
"bindings": [
"/display_name",
"/first_name",
"/preferred_contact",
"/source"
],
"byte_size": 3539,
"content_hash": "302f1d78302d094df37225b1b9e0e463a5516937da347874d24373187f00ef1e",
"media_type": "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
}
