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

ExamplesExemple · API 0.8.0

release-immutability

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

release-immutability/curl.sh · 2710 bytes · sha256 6f2a82e0e9f72e14…
#!/bin/sh
# Docula example: releases are immutable.
# login -> publish a release -> publish the same body again and expect HTTP 409 (Problem code "conflict").
# Requires curl and jq. Environment: DOCULA_API, DOCULA_ORIGIN (defaults to DOCULA_API), DOCULA_USERNAME, DOCULA_PASSWORD,
# and the four published identities the release freezes: DOCULA_CONTRACT_VERSION_ID, DOCULA_TRANSFORM_VERSION_ID,
# DOCULA_TEMPLATE_VERSION_ID, DOCULA_CASE_ID (a valid or boundary case of that contract version).
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" "$JAR.problem"' 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. Substitute your published identities into the recorded body.
jq --arg c "${DOCULA_CONTRACT_VERSION_ID:?}" --arg t "${DOCULA_TRANSFORM_VERSION_ID:?}" \
   --arg d "${DOCULA_TEMPLATE_VERSION_ID:?}" --arg k "${DOCULA_CASE_ID:?}" \
   '.contract_version_id = $c | .transform_version_id = $t | .template_version_id = $d | .case_id = $k' \
   "$HERE/publish-release.request.json" > "$JAR.body"

# 2. Publish (publishRelease). 201 returns the release with its content_hash and canonical manifest.
RELEASE=$(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/releases")
printf '%s' "$RELEASE" | jq '{id: .release.id, content_hash: .release.content_hash, published_at: .release.published_at}'

# 3. Publish the identical body again. The manifest hashes to the same content_hash, which is unique,
#    so the API answers 409 with an application/problem+json body instead of a second release.
STATUS=$(curl --silent --show-error -b "$JAR" -X POST -H "Origin: $ORIGIN" -H "X-CSRF-Token: $CSRF" \
  -H 'Content-Type: application/json' --data-binary @"$JAR.body" -o "$JAR.problem" -w '%{http_code}' "$API/api/v1/releases")
[ "$STATUS" = 409 ] || { echo "expected 409 on republish, got $STATUS" >&2; exit 1; }
jq -e '.code == "conflict" and .type == "/problems/conflict" and .status == 409' "$JAR.problem" > /dev/null
jq '.' "$JAR.problem"

# 4. Reading the release back returns the same immutable manifest; there is no update or delete operation.
curl --fail --silent --show-error -b "$JAR" "$API/api/v1/releases/$(printf '%s' "$RELEASE" | jq -r '.release.id')" | jq -r '.content_hash'
release-immutability/fixture.json · 1289 bytes · sha256 eff76e57e746dc8c…
{
  "schema": "docula.example-fixture/v1",
  "slug": "release-immutability",
  "guide": "/developers/guides/releases-and-immutability",
  "title": "Releases and immutability",
  "summary": "The legacy publishRelease body used by the operational release page (exact contract, transform, template and case identities), the curl sequence that publishes it, and the 409 problem document the API returns when the identical release is published a second time.",
  "operations": ["login", "publishRelease", "getRelease"],
  "related": ["execution-trace", "docx-template"],
  "files": [
    { "path": "publish-release.request.json", "purpose": "publishRelease body (legacy document-generation shape); UUIDs are placeholders replaced by curl.sh.", "validate": { "kind": "openapi", "schema": "#/components/schemas/PublishReleaseRequest" } },
    { "path": "republish-conflict.problem.json", "purpose": "application/problem+json returned on a second identical publish: 409 conflict.", "validate": { "kind": "openapi", "schema": "#/components/schemas/Problem", "expect": { "/status": 409, "/code": "conflict", "/type": "/problems/conflict" } } },
    { "path": "curl.sh", "purpose": "Publish once, publish again, assert 409, read the immutable manifest back.", "validate": { "kind": "shell" } }
  ]
}
release-immutability/publish-release.request.json · 423 bytes · sha256 7bf1099074b29483…
{
  "name": "Person welcome letter",
  "description": "Docs example: exact contract, transform, template and validation case identities frozen into one immutable release.",
  "contract_version_id": "11111111-1111-4111-8111-000000000001",
  "transform_version_id": "22222222-2222-4222-8222-000000000001",
  "template_version_id": "33333333-3333-4333-8333-000000000001",
  "case_id": "44444444-4444-4444-8444-000000000001"
}
release-immutability/republish-conflict.problem.json · 221 bytes · sha256 14dd3297b12a4ab2…
{
  "type": "/problems/conflict",
  "title": "Conflict",
  "status": 409,
  "code": "conflict",
  "detail": "The resource changed. Reload and compare before retrying.",
  "correlation_id": "docs-example-correlation-id"
}