DoculaDevelopersDezvoltatori
API 0.8.0 · BuildVersiune produs 0.33.0
Documentation navigationNavigare documentație

ExamplesExemple · API 0.8.0

declarative-transform

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

declarative-transform/contract.json · 505 bytes · sha256 78d18c0ad890c899…
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "Person",
  "type": "object",
  "additionalProperties": false,
  "required": ["first_name", "last_name", "email"],
  "properties": {
    "first_name": { "type": "string", "minLength": 1 },
    "middle_name": { "type": "string", "minLength": 1 },
    "last_name": { "type": "string", "minLength": 1 },
    "email": { "type": "string", "format": "email" },
    "phone": { "type": "string", "pattern": "^\\+[1-9][0-9]{6,14}$" }
  }
}
declarative-transform/create-contract.request.json · 730 bytes · sha256 0a6751820334bfc2…
{
  "name": "Person",
  "description": "Docs example: the person intake contract used by the declarative transform guide.",
  "schema": "{\n  \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n  \"title\": \"Person\",\n  \"type\": \"object\",\n  \"additionalProperties\": false,\n  \"required\": [\"first_name\", \"last_name\", \"email\"],\n  \"properties\": {\n    \"first_name\": { \"type\": \"string\", \"minLength\": 1 },\n    \"middle_name\": { \"type\": \"string\", \"minLength\": 1 },\n    \"last_name\": { \"type\": \"string\", \"minLength\": 1 },\n    \"email\": { \"type\": \"string\", \"format\": \"email\" },\n    \"phone\": { \"type\": \"string\", \"pattern\": \"^\\\\+[1-9][0-9]{6,14}$\" }\n  }\n}\n"
}
declarative-transform/create-transform.request.json · 771 bytes · sha256 1ced46d12a123992…
{
  "name": "Person welcome projection",
  "description": "Docs example: copies, concatenates and coalesces person fields.",
  "source": "{\n  \"language\": \"declarative-v1\",\n  \"output\": {\n    \"first_name\": { \"$copy\": \"/first_name\" },\n    \"middle_name\": { \"$copy_optional\": \"/middle_name\" },\n    \"display_name\": {\n      \"$concat\": [\n        { \"$copy\": \"/first_name\" },\n        { \"$literal\": \" \" },\n        { \"$copy\": \"/last_name\" }\n      ]\n    },\n    \"preferred_contact\": {\n      \"$coalesce\": [\n        { \"$copy_optional\": \"/phone\" },\n        { \"$copy_optional\": \"/email\" },\n        { \"$literal\": \"none\" }\n      ]\n    },\n    \"source\": { \"$literal\": \"docs-example\" }\n  }\n}\n",
  "format": "json"
}
declarative-transform/create-version.request.json · 29 bytes · sha256 c33d261b7a5878fd…
{
  "expected_revision": 1
}
declarative-transform/curl.sh · 3419 bytes · sha256 a5fd68d7d9ae80bb…
#!/bin/sh
# Docula example: declarative transform.
# login -> create contract -> create version -> publish -> create transform -> create version -> publish.
# Requires curl and jq. Environment: DOCULA_API (API origin, e.g. https://docula.ro),
# DOCULA_ORIGIN (browser origin accepted by the API; defaults to DOCULA_API),
# DOCULA_USERNAME and DOCULA_PASSWORD (read from the environment, never stored here).
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"' EXIT

# 1. Login. The session cookie goes to the cookie jar; the CSRF token comes back in the JSON body.
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')

# api METHOD PATH [JSON-FILE]: every mutation needs the exact Origin, the session cookie and X-CSRF-Token.
api() {
  if [ "$#" -ge 3 ]; then
    curl --fail --silent --show-error -b "$JAR" -X "$1" -H "Origin: $ORIGIN" -H "X-CSRF-Token: $CSRF" \
      -H 'Content-Type: application/json' --data-binary @"$3" "$API$2"
  else
    curl --fail --silent --show-error -b "$JAR" -X "$1" -H "Origin: $ORIGIN" -H "X-CSRF-Token: $CSRF" "$API$2"
  fi
}

# 2. Create the contract draft (createContract). The schema travels as a JSON string.
CONTRACT=$(api POST /api/v1/contracts "$HERE/create-contract.request.json")
CONTRACT_ID=$(printf '%s' "$CONTRACT" | jq -r '.contract.id')
REVISION=$(printf '%s' "$CONTRACT" | jq -r '.contract.draft_revision')

# 3. Freeze the draft into version 1 (createContractVersion) using the draft revision you just read.
VERSION=$(jq --argjson rev "$REVISION" '.expected_revision = $rev' "$HERE/create-version.request.json" > "$JAR.body" && api POST "/api/v1/contracts/$CONTRACT_ID/versions" "$JAR.body")
CONTRACT_VERSION_ID=$(printf '%s' "$VERSION" | jq -r '.version.id')
CONTRACT_VERSION_NUMBER=$(printf '%s' "$VERSION" | jq -r '.version.number')

# 4. Publish the version (publishContractVersion). The body is an empty JSON object.
api POST "/api/v1/contracts/$CONTRACT_ID/versions/$CONTRACT_VERSION_NUMBER/publish" "$HERE/publish.request.json" > /dev/null

# 5. Create the transform draft (createTransform). The declarative-v1 program travels as a JSON string.
TRANSFORM=$(api POST /api/v1/transforms "$HERE/create-transform.request.json")
TRANSFORM_ID=$(printf '%s' "$TRANSFORM" | jq -r '.transform.id')
TRANSFORM_REVISION=$(printf '%s' "$TRANSFORM" | jq -r '.transform.draft_revision')

# 6. Freeze and publish transform version 1 (createTransformVersion, publishTransformVersion).
jq --argjson rev "$TRANSFORM_REVISION" '.expected_revision = $rev' "$HERE/create-version.request.json" > "$JAR.body"
TRANSFORM_VERSION=$(api POST "/api/v1/transforms/$TRANSFORM_ID/versions" "$JAR.body")
TRANSFORM_VERSION_ID=$(printf '%s' "$TRANSFORM_VERSION" | jq -r '.version.id')
TRANSFORM_VERSION_NUMBER=$(printf '%s' "$TRANSFORM_VERSION" | jq -r '.version.number')
api POST "/api/v1/transforms/$TRANSFORM_ID/versions/$TRANSFORM_VERSION_NUMBER/publish" "$HERE/publish.request.json" > /dev/null
rm -f "$JAR.body"

printf 'contract_version_id=%s\ntransform_version_id=%s\n' "$CONTRACT_VERSION_ID" "$TRANSFORM_VERSION_ID"
declarative-transform/expected-output.json · 138 bytes · sha256 c1143b19e46631cc…
{"display_name":"Iulia Popescu","first_name":"Iulia","middle_name":null,"preferred_contact":"[email protected]","source":"docs-example"}
declarative-transform/fixture.json · 2800 bytes · sha256 ebf292f76fff3407…
{
  "schema": "docula.example-fixture/v1",
  "slug": "declarative-transform",
  "guide": "/developers/guides/declarative-v1-transforms",
  "title": "Declarative-v1 transform",
  "summary": "A person contract, a declarative-v1 program that uses every course operator ($copy, $copy_optional, $literal, $concat, $coalesce), a sample input, the exact output produced by the engine, and the curl sequence that publishes both the contract and the transform.",
  "operations": ["login", "createContract", "createContractVersion", "publishContractVersion", "createTransform", "createTransformVersion", "publishTransformVersion"],
  "related": ["contract-versioning", "docx-template"],
  "transform": {
    "definition": "transform.json",
    "input": "input.json",
    "expectedOutput": "expected-output.json",
    "authority": "internal/transforms/examples_fixture_test.go"
  },
  "files": [
    { "path": "contract.json", "purpose": "JSON Schema 2020-12 contract the input must satisfy.", "validate": { "kind": "json-schema-2020-12" } },
    { "path": "transform.json", "purpose": "declarative-v1 program: copy, optional copy, literal, concat and coalesce.", "validate": { "kind": "declarative-v1" } },
    { "path": "input.json", "purpose": "Sample input case; satisfies contract.json and omits the optional fields.", "validate": { "kind": "instance", "schemaFile": "contract.json" } },
    { "path": "expected-output.json", "purpose": "Canonical JSON produced by the engine for input.json; regenerated by the Go test.", "validate": { "kind": "json" }, "authority": "internal/transforms/examples_fixture_test.go" },
    { "path": "create-contract.request.json", "purpose": "createContract body; schema embeds contract.json as a string.", "validate": { "kind": "openapi", "schema": "#/components/schemas/CreateContractRequest" }, "embeds": [{ "field": "schema", "file": "contract.json" }] },
    { "path": "create-transform.request.json", "purpose": "createTransform body; source embeds transform.json as a string.", "validate": { "kind": "openapi", "schema": "#/components/schemas/CreateTransformRequest", "expect": { "/format": "json" } }, "embeds": [{ "field": "source", "file": "transform.json" }] },
    { "path": "create-version.request.json", "purpose": "createContractVersion / createTransformVersion body carrying the expected draft revision.", "validate": { "kind": "openapi", "schema": "#/components/schemas/RevisionRequest" } },
    { "path": "publish.request.json", "purpose": "publishContractVersion / publishTransformVersion body: an empty JSON object.", "validate": { "kind": "openapi", "schema": "#/components/schemas/EmptyObject" } },
    { "path": "curl.sh", "purpose": "Login, create and publish the contract, create and publish the transform.", "validate": { "kind": "shell" } }
  ]
}
declarative-transform/input.json · 87 bytes · sha256 90a29afa7c31dcf9…
{
  "first_name": "Iulia",
  "last_name": "Popescu",
  "email": "[email protected]"
}
declarative-transform/publish.request.json · 3 bytes · sha256 ca3d163bab055381…
{}
declarative-transform/transform.json · 531 bytes · sha256 aa969a3ce067413d…
{
  "language": "declarative-v1",
  "output": {
    "first_name": { "$copy": "/first_name" },
    "middle_name": { "$copy_optional": "/middle_name" },
    "display_name": {
      "$concat": [
        { "$copy": "/first_name" },
        { "$literal": " " },
        { "$copy": "/last_name" }
      ]
    },
    "preferred_contact": {
      "$coalesce": [
        { "$copy_optional": "/phone" },
        { "$copy_optional": "/email" },
        { "$literal": "none" }
      ]
    },
    "source": { "$literal": "docs-example" }
  }
}