APIZDocs

APIZ guide

Structured Policy Tutorial

Build a General API Policy that allows GET and HEAD requests and denies every write method. The tutorial uses the built-in General API read only project and two credential-free Fixtures.

WHEN action is http:get or http:head
THEN allow with reason read_request_allowed
OTHERWISE deny with reason write_request_not_allowed

Complete either the Web Console or CLI path. Both publish the same Policy Project contract.

Before You Start

  • Create a General API Instance and bind it to a Client.
  • Keep the Client Binding private.
  • Use synthetic Fixture paths. They do not need to exist on the upstream API.
  • For the final live check, choose a real read path and a harmless write request suitable for your own test upstream.

Web Console

1. Create From The Structured Example

  1. Open Policies and select Create Policy.
  2. Choose Structured.
  3. Select the General API adapter scope.
  4. Under Start from an example, choose General API read only.
  5. Review the name, description, and two Fixtures, then select Create from example.

Creation produces an inactive Policy and a Working Draft. It does not affect traffic, contact the upstream API, or attach itself.

2. Inspect The Guided Definition

Policy Studio opens structured.policy in Form view. Confirm:

  • WHEN contains actions http:get and http:head;
  • THEN is allow with reason read_request_allowed;
  • OTHERWISE is deny with reason write_request_not_allowed.

Use YAML or JSON only when you need the complete portable definition. After editing source view, select Apply source before Save, Run, or Review publication. Invalid or unapplied source cannot silently leave an older definition active.

3. Inspect And Run The Draft Fixtures

In the Studio Explorer, open both Fixtures:

  • Allow a GET request sends synthetic GET /v1/items and expects allow;
  • Deny a POST request sends synthetic POST /v1/items and expects deny.

Fixtures contain no credentials and do not reach the upstream service. Select Run, then Run all enabled Fixtures. The Studio saves the exact in-memory Draft when needed, validates it, runs both cases, and opens the result panel.

Do not continue until both Fixtures pass and their actual reasons match the expectations.

4. Publish And Establish Readiness

  1. Select Review publication. APIZ saves and compiles as needed. Review the changes and traffic effect, then confirm the next Published Revision.
  2. On Policy detail, open Run tests.
  3. Select Run full suite.
  4. Confirm Published suite passed. Readiness is stored against this exact Published Revision and content hash.
  5. Return to Policy detail or the list and select Enable Policy.

Publishing promotes definition and Fixtures atomically. It does not enable or attach the Policy.

5. Attach To One Client Binding

  1. Open Clients and select the Client used for this tutorial.
  2. Find its General API Binding under API Access.
  3. Expand Policies.
  4. Choose the new Policy and select Attach Policy.
  5. Keep it required with execution order 100.

Active Policies appear regardless of test state. Testing is optional; notices distinguish absent, failed, and outdated evidence without blocking attachment.

6. Verify Allow, Deny, And Evidence

Issue a short-lived Temporary Credential for the Binding, then send:

  1. a safe GET to a real read path: it should pass Policy and reach upstream;
  2. a harmless POST or other write request: APIZ should deny it before Secret Broker release and before upstream traffic.

Open Logs / AuditAccess Logs, filter by the Client, and compare the two rows. The denied request should show write_request_not_allowed; the allowed request should show the upstream result. Neither row may contain a Temporary Credential or upstream credential value.

CLI

1. Create The Policy Project

Create this directory outside a repository that might accidentally commit runtime secrets:

general-read-only/
├── apiz-policy.json
└── fixtures/
    ├── allow-get.json
    └── deny-post.json

apiz-policy.json:

{
  "api_version": "apiz.io/v1",
  "kind": "PolicyProject",
  "metadata": {
    "name": "General API read only",
    "description": "Allow GET and HEAD requests while denying every write method."
  },
  "config": {
    "type": "structured",
    "adapter_scope": "general",
    "definition": {
      "when": { "actions": ["http:get", "http:head"] },
      "then": { "decision": "allow", "reason": "read_request_allowed" },
      "otherwise": { "decision": "deny", "reason": "write_request_not_allowed" }
    }
  },
  "code": null,
  "fixtures": [
    { "file": "fixtures/allow-get.json" },
    { "file": "fixtures/deny-post.json" }
  ]
}

fixtures/allow-get.json:

{
  "metadata": {
    "key": "allow-get",
    "name": "Allow a GET request",
    "enabled": true,
    "adapter_id": "general"
  },
  "request": { "method": "GET", "path": "/v1/items" },
  "expectation": { "decision": "allow", "reason": "read_request_allowed" }
}

fixtures/deny-post.json:

{
  "metadata": {
    "key": "deny-post",
    "name": "Deny a POST request",
    "enabled": true,
    "adapter_id": "general"
  },
  "request": { "method": "POST", "path": "/v1/items" },
  "expectation": { "decision": "deny", "reason": "write_request_not_allowed" }
}

Fixtures must remain synthetic and credential-free.

2. Publish The Project

The CLI first saves and compiles a Structured project into a reviewed Working Draft. It does not currently run a Structured project locally with policy test --project.

umask 077
apiz -o json policy publish --project ./general-read-only \
  > structured-policy-review.json
POLICY_ID=$(jq -r '.candidate.policy_id' structured-policy-review.json)
DRAFT_REVISION=$(jq -r '.candidate.draft_revision' structured-policy-review.json)
POLICY_REVISION=$(jq -r '.candidate.current_published_revision' structured-policy-review.json)

jq '{candidate, changes, evidence, traffic_effect}' structured-policy-review.json
apiz -o json policy publish "$POLICY_ID" --project ./general-read-only \
  --expected-draft-revision "$DRAFT_REVISION" \
  --expected-policy-revision "$POLICY_REVISION" \
  --confirm > structured-policy-publish.json

When no Policy id is supplied, policy publish creates an inactive Policy, saves the Working Draft, performs authoritative validation/compile, and returns the review without publishing. The confirmation publishes only the exact reviewed definition and Fixtures. To update the same Policy, prepare another review using its id and the current Draft revision shown by policy draft show:

apiz policy publish "$POLICY_ID" --project ./general-read-only \
  --expected-draft-revision <current-draft-revision>

3. Run The Published Suite And Enable

apiz policy test-suite "$POLICY_ID"
apiz policy enable "$POLICY_ID"

The published suite is recommended evidence for this tutorial, not a publish or attachment gate. If it is absent or failed, Web and CLI should warn about the exact evidence state while still allowing an authorized attachment.

4. Attach To The Client Binding

apiz client binding policy add <client-binding-id> \
  --policy "$POLICY_ID" \
  --order 100

The binding is required by default. Do not add --optional for this tutorial.

5. Verify And Inspect Evidence

Use a Temporary Credential for the bound Client to send one safe read and one harmless write request. Then inspect:

apiz access-log list --client <client-id> --since 15m --limit 50
apiz access-log request <request-id>

Confirm that the read reached upstream, the write was denied with write_request_not_allowed, and the denied request did not release the upstream credential.

Change Or Remove The Policy

  • Edit and republish a new revision before changing live behavior.
  • Re-run the full published suite after every publish.
  • Disable or remove the Policy Binding to stop applying it to this route.
  • Disabling a Policy is different from revoking the Client's Temporary Credential or rotating the upstream credential.

Next: Scripted Policy tutorial.