Generic REST Orchestration

Prev Next

Overview

Any orchestration tool that can make REST API calls can integrate with Validatar. This guide provides complete, copy-paste-ready scripts in Python, PowerShell, and Bash for the execute-poll-evaluate pattern. Adapt these for your specific orchestrator.

Prerequisites

  • Validatar API token with the Execution scope enabled — see User Tokens
  • Network access from your orchestration environment to the Validatar API endpoint
  • Your Validatar project ID and job ID (visible in the Validatar UI URL)

Example: Execute a Job and Evaluate Results (Python)

import requests
import time
import os
import sys

# ---------------------------------------------------------------------------
# Configuration — set these as environment variables or replace inline
# ---------------------------------------------------------------------------
VALIDATAR_API_URL = os.environ.get("VALIDATAR_API_URL")       # e.g., https://mycompany.cloud.validatar.com
VALIDATAR_API_TOKEN = os.environ.get("VALIDATAR_API_TOKEN")
PROJECT_ID = int(os.environ.get("VALIDATAR_PROJECT_ID", "0"))
JOB_ID = int(os.environ.get("VALIDATAR_JOB_ID", "0"))

POLL_INTERVAL_SECONDS = 5
TIMEOUT_SECONDS = int(os.environ.get("VALIDATAR_TIMEOUT", "1800"))  # 30 minutes default

HEADERS = {
    "x-val-api-token": VALIDATAR_API_TOKEN,
    "Content-Type": "application/json"
}

BASE = f"{VALIDATAR_API_URL}/core/api/v1"

# ---------------------------------------------------------------------------
# Step 1 — Execute the job
# ---------------------------------------------------------------------------
print(f"Executing job {JOB_ID} in project {PROJECT_ID}...")

execute_url = f"{BASE}/projects/{PROJECT_ID}/jobs/{JOB_ID}/execute"
response = requests.post(execute_url, headers=HEADERS)
response.raise_for_status()

execution = response.json()
batch_key = execution["executionKey"]
print(f"Execution started. Batch key: {batch_key}")

# ---------------------------------------------------------------------------
# Step 2 — Poll for results
# ---------------------------------------------------------------------------
results_url = f"{BASE}/projects/{PROJECT_ID}/jobs/{JOB_ID}/results/{batch_key}"
elapsed = 0

while elapsed < TIMEOUT_SECONDS:
    time.sleep(POLL_INTERVAL_SECONDS)
    elapsed += POLL_INTERVAL_SECONDS

    poll_response = requests.get(results_url, headers=HEADERS)
    poll_response.raise_for_status()

    result = poll_response.json()
    status = result.get("status", "Unknown")
    print(f"  [{elapsed}s] Status: {status}")

    if status in ("Completed", "Aborted", "Abandoned"):
        break
else:
    print(f"ERROR: Timeout after {TIMEOUT_SECONDS} seconds. Job may still be running.")
    sys.exit(1)

# ---------------------------------------------------------------------------
# Step 3 — Evaluate results
# ---------------------------------------------------------------------------
print(f"\nJob finished with status: {status}")
print(f"  Started:   {result.get('dateStarted')}")
print(f"  Completed: {result.get('dateCompleted')}")

if status != "Completed":
    print(f"FAILED: Job ended with status '{status}'.")
    sys.exit(1)

# Check individual test results within the job
tests = result.get("tests", [])
failed_tests = [t for t in tests if t.get("status") not in ("Passed", "Completed")]

if failed_tests:
    print(f"\n{len(failed_tests)} test(s) did not pass:")
    for t in failed_tests:
        print(f"  - {t.get('name')} (ID: {t.get('id')}): {t.get('status')}")
    sys.exit(1)

print(f"All {len(tests)} test(s) passed. Pipeline may continue.")
sys.exit(0)

Example: Execute a Job and Evaluate Results (PowerShell)

# ---------------------------------------------------------------------------
# Configuration — set these as environment variables or replace inline
# ---------------------------------------------------------------------------
$ValidatarApiUrl   = $env:VALIDATAR_API_URL        # e.g., https://mycompany.cloud.validatar.com
$ValidatarApiToken = $env:VALIDATAR_API_TOKEN
$ProjectId         = [int]$env:VALIDATAR_PROJECT_ID
$JobId             = [int]$env:VALIDATAR_JOB_ID

$PollIntervalSeconds = 5
$TimeoutSeconds      = if ($env:VALIDATAR_TIMEOUT) { [int]$env:VALIDATAR_TIMEOUT } else { 1800 }

$Headers = @{
    "x-val-api-token" = $ValidatarApiToken
    "Content-Type"    = "application/json"
}

$Base = "$ValidatarApiUrl/core/api/v1"

# ---------------------------------------------------------------------------
# Compatibility — TLS 1.2 for Windows PowerShell 5.1
# ---------------------------------------------------------------------------
if ($PSVersionTable.PSVersion.Major -le 5) {
    [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
}

# ---------------------------------------------------------------------------
# Step 1 — Execute the job
# ---------------------------------------------------------------------------
Write-Host "Executing job $JobId in project $ProjectId..."

$ExecuteUrl = "$Base/projects/$ProjectId/jobs/$JobId/execute"

try {
    $ExecuteResponse = Invoke-RestMethod -Uri $ExecuteUrl -Method Post -Headers $Headers -ErrorAction Stop
}
catch {
    Write-Error "Failed to execute job: $_"
    exit 1
}

$BatchKey = $ExecuteResponse.executionKey
Write-Host "Execution started. Batch key: $BatchKey"

# ---------------------------------------------------------------------------
# Step 2 — Poll for results
# ---------------------------------------------------------------------------
$ResultsUrl = "$Base/projects/$ProjectId/jobs/$JobId/results/$BatchKey"
$Elapsed = 0
$Status = "Running"

while ($Elapsed -lt $TimeoutSeconds) {
    Start-Sleep -Seconds $PollIntervalSeconds
    $Elapsed += $PollIntervalSeconds

    try {
        $PollResponse = Invoke-RestMethod -Uri $ResultsUrl -Method Get -Headers $Headers -ErrorAction Stop
    }
    catch {
        Write-Warning "Poll request failed at ${Elapsed}s: $_. Retrying..."
        continue
    }

    $Status = $PollResponse.status
    Write-Host "  [${Elapsed}s] Status: $Status"

    if ($Status -in @("Completed", "Aborted", "Abandoned")) {
        break
    }
}

if ($Elapsed -ge $TimeoutSeconds -and $Status -eq "Running") {
    Write-Error "Timeout after $TimeoutSeconds seconds. Job may still be running."
    exit 1
}

# ---------------------------------------------------------------------------
# Step 3 — Evaluate results
# ---------------------------------------------------------------------------
Write-Host "`nJob finished with status: $Status"
Write-Host "  Started:   $($PollResponse.dateStarted)"
Write-Host "  Completed: $($PollResponse.dateCompleted)"

if ($Status -ne "Completed") {
    Write-Error "Job ended with status '$Status'."
    exit 1
}

# Check individual test results within the job
$Tests = $PollResponse.tests
$FailedTests = $Tests | Where-Object { $_.status -notin @("Passed", "Completed") }

if ($FailedTests) {
    Write-Host "`n$($FailedTests.Count) test(s) did not pass:"
    foreach ($t in $FailedTests) {
        Write-Host "  - $($t.name) (ID: $($t.id)): $($t.status)"
    }
    exit 1
}

Write-Host "All $($Tests.Count) test(s) passed. Pipeline may continue."
exit 0

Example: Execute a Job (Bash/curl)

#!/usr/bin/env bash
set -euo pipefail

# ---------------------------------------------------------------------------
# Configuration
# ---------------------------------------------------------------------------
VALIDATAR_API_URL="${VALIDATAR_API_URL:?Set VALIDATAR_API_URL}"
VALIDATAR_API_TOKEN="${VALIDATAR_API_TOKEN:?Set VALIDATAR_API_TOKEN}"
PROJECT_ID="${VALIDATAR_PROJECT_ID:?Set VALIDATAR_PROJECT_ID}"
JOB_ID="${VALIDATAR_JOB_ID:?Set VALIDATAR_JOB_ID}"

POLL_INTERVAL=5
TIMEOUT="${VALIDATAR_TIMEOUT:-1800}"

BASE="${VALIDATAR_API_URL}/core/api/v1"

# ---------------------------------------------------------------------------
# Step 1 — Execute
# ---------------------------------------------------------------------------
echo "Executing job ${JOB_ID} in project ${PROJECT_ID}..."

EXEC_RESPONSE=$(curl -s -f -X POST \
  "${BASE}/projects/${PROJECT_ID}/jobs/${JOB_ID}/execute" \
  -H "x-val-api-token: ${VALIDATAR_API_TOKEN}" \
  -H "Content-Type: application/json")

BATCH_KEY=$(echo "${EXEC_RESPONSE}" | python3 -c "import sys,json; print(json.load(sys.stdin)['executionKey'])")
echo "Execution started. Batch key: ${BATCH_KEY}"

# ---------------------------------------------------------------------------
# Step 2 — Poll
# ---------------------------------------------------------------------------
RESULTS_URL="${BASE}/projects/${PROJECT_ID}/jobs/${JOB_ID}/results/${BATCH_KEY}"
ELAPSED=0
STATUS="Running"

while [ "${ELAPSED}" -lt "${TIMEOUT}" ]; do
  sleep "${POLL_INTERVAL}"
  ELAPSED=$((ELAPSED + POLL_INTERVAL))

  POLL_RESPONSE=$(curl -s -f -X GET "${RESULTS_URL}" \
    -H "x-val-api-token: ${VALIDATAR_API_TOKEN}")

  STATUS=$(echo "${POLL_RESPONSE}" | python3 -c "import sys,json; print(json.load(sys.stdin).get('status','Unknown'))")
  echo "  [${ELAPSED}s] Status: ${STATUS}"

  if [[ "${STATUS}" == "Completed" || "${STATUS}" == "Aborted" || "${STATUS}" == "Abandoned" ]]; then
    break
  fi
done

if [[ "${STATUS}" == "Running" ]]; then
  echo "ERROR: Timeout after ${TIMEOUT}s"
  exit 1
fi

# ---------------------------------------------------------------------------
# Step 3 — Evaluate
# ---------------------------------------------------------------------------
if [[ "${STATUS}" != "Completed" ]]; then
  echo "FAILED: Job ended with status '${STATUS}'"
  exit 1
fi

echo "Job completed successfully."
exit 0

Example: Execute a Standard Test with waitUntilComplete (Python)

For individual standard tests, you can skip polling entirely by setting waitUntilComplete to true. The API call blocks until the test finishes and returns the result directly.

import requests
import os
import sys

VALIDATAR_API_URL = os.environ.get("VALIDATAR_API_URL")
VALIDATAR_API_TOKEN = os.environ.get("VALIDATAR_API_TOKEN")
PROJECT_ID = int(os.environ.get("VALIDATAR_PROJECT_ID", "0"))
TEST_ID = int(os.environ.get("VALIDATAR_TEST_ID", "0"))

HEADERS = {
    "x-val-api-token": VALIDATAR_API_TOKEN,
    "Content-Type": "application/json"
}

BASE = f"{VALIDATAR_API_URL}/core/api/v1"

# Execute synchronously — no polling needed
print(f"Executing standard test {TEST_ID} (synchronous)...")

execute_url = f"{BASE}/projects/{PROJECT_ID}/tests/{TEST_ID}/execute"
payload = {
    "saveInRepository": True,
    "waitUntilComplete": True
}

response = requests.post(execute_url, headers=HEADERS, json=payload)
response.raise_for_status()

execution = response.json()
batch_key = execution["executionKey"]
print(f"Execution complete. Batch key: {batch_key}")

# Get the summary to check the result
summary_url = f"{BASE}/projects/{PROJECT_ID}/tests/{TEST_ID}/results/{batch_key}"
summary_response = requests.get(summary_url, headers=HEADERS)
summary_response.raise_for_status()

summary = summary_response.json()
result = summary.get("result", "Unknown")

print(f"Test: {summary.get('name')}")
print(f"Result: {result}")
print(f"Started: {summary.get('dateStarted')}")
print(f"Completed: {summary.get('dateCompleted')}")

if result == "Passed":
    print("Test passed. Pipeline may continue.")
    sys.exit(0)
else:
    print(f"Test did not pass (result: {result}).")
    sys.exit(1)

Adapting for Your Orchestrator

The scripts above work anywhere you can run Python, PowerShell, or Bash. Here's how to call them from common orchestration platforms:

Orchestrator How to Run Notes
Control-M Web Services job type or OS job running a script Use the Python or PowerShell script as the job command
Prefect @task decorator calling requests in a flow Wrap the Python logic in a Prefect task; use Prefect Blocks for credentials
Dagster @op decorator with requests in a job Wrap the Python logic in a Dagster op; use Resources for credentials
dbt Cloud Webhooks triggering an external script dbt Cloud can call a webhook on model completion; the webhook runs the Validatar script
Luigi Task subclass with requests in run() Wrap the Python logic in a Luigi Task
SSIS Execute Process task running PowerShell Point the task at the PowerShell script; pass parameters via SSIS variables
Talend tSystem component or tRESTClient Use tSystem to call the script, or tRESTClient for direct API calls

Troubleshooting

401 or 403 Response

  • Verify the x-val-api-token header name is exact (not Authorization or Bearer)
  • Confirm the token has the Execution scope
  • Check that the token user has access to the project

Timeout Without Completion

  • Increase TIMEOUT_SECONDS if your jobs are expected to run longer than 30 minutes
  • Check the Validatar UI to see if the execution is still running or has an error
  • Verify the job has tests assigned to it — an empty job may behave unexpectedly

Connection Refused or Timeout

  • Verify VALIDATAR_API_URL is correct (e.g., https://mycompany.cloud.validatar.com)
  • Check network connectivity — if Validatar Server is behind a firewall, the orchestrator must be able to reach it
  • For Cloud instances, verify no corporate proxy is blocking the connection

Empty Test Results in Job Summary

  • The tests array in the job summary may not be populated until the job status is Completed
  • Ensure you're reading the final poll response, not an intermediate one