Skip to content

Simple yet powerful CLI tool for defining and running end-to-end API test flows using a simple JSON configuration file.

License

Notifications You must be signed in to change notification settings

okira-e/veriflow

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

37 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Veriflow

Veriflow is a simple yet powerful CLI tool for defining and running end-to-end API test flows using a simple JSON configuration file.

promo

Index

Overview

{
    "baseUrl": "http://localhost:8080",
    "flows": {
        "user-auth": {
            "steps": [
                {
                    "name": "register",
                    "request": {
                        "method": "POST",
                        "path": "/api/auth/v3/register",
                        "json": {
                            "email": "user+{{RUN_ID}}@example.com", // RUN ID injectable
                            "password": "secret"
                        }
                    },
                    "assert": {
                        "status": 201,
                        "all": [{ "jsonpath": "$.data.username", "exists": true }]
                    },
                    "exports": { "username": "$.data.username" } // Export variable for next requests
                },
                {
                    "name": "login", // auth headers/cookies are persisted automatically
                    "request": {
                        "method": "POST",
                        "path": "/api/auth/v3/login",
                        "json": {
                            "username": "{{bind:username}}", // Use a defined var
                            "password": "secret"
                        }
                    },
                    "assert": {
                        "status": 200,
                        "all": [{ "jsonpath": "$.data.email", "contains": "{{RUN_ID}}" }]
                    }
                },
                // ...
            ]
        }
    }
}

Why Veriflow

Because it's the simplest form of targeted flow testing that:

  • Treats your API as a black box
  • Runs ordered, stateful flows (auth -> action -> verify)
  • Passes data between steps (JWTs, IDs, etc.)
  • Requires zero code changes in your server

If your API works, Veriflow passes. If it doesn't, it fails. Simple.

Project Status

Veriflow is production-ready with continuous features and general enhancements.

Expect:

  • Minor config changes
  • Better error messages
  • Improved reporting

Core concepts are stable.

Concepts

Flow

Represents a real user or system journey.

Example:

  • user-onboarding
  • checkout
  • admin-create-user

Flows are ordered. If a step fails, the flow stops.

Step

A step is a single HTTP request with assertions.

Each step defines:

  • HTTP method + path
  • Request body / headers / files
  • Assertions on the response
  • Optional exported values for the next steps

Exports

You can extract values from a response and reuse them later.

Common use cases:

  • JWT tokens
  • User ID created in a test to be asserted in the following GET request

Exports are resolved via JSONPath (for JSON responses) or XPath (for XML responses).

Assertions

Veriflow supports:

  • Status code checks
  • JSONPath existence / equality / containment (for JSON responses)
  • XPath existence / equality / containment (for XML responses)

Assertions are explicit. No magic.

Content Type Support

Veriflow automatically detects response content types and uses the appropriate parser:

  • JSON: Uses JSONPath for assertions and exports (e.g., $.data.user.id)
  • XML: Uses XPath for assertions and exports (e.g., /response/data/user/id)

You can send JSON, XML, or files in your requests using the json, xml, or files fields.

Installation

go install github.com/okira-e/veriflow@latest

Or download a prebuilt binary from releases.

Quick Start

veriflow init

This creates a veriflow.json at the project root.

veriflow run

Runs all flows.

veriflow run user-onboarding

Runs a single flow.

Design Principles

  • Black-box testing only
  • Deterministic execution
  • Explicit over implicit
  • No framework assumptions
  • Human-readable configs

Documentation

Configuration Reference

The configuration file (veriflow.json) has the following structure:

{
    "projectName": "my-api-tests",
    "baseUrl": "http://localhost:3000",
    "beforeRun": ["echo 'Starting tests'"],
    "afterRun": ["echo 'Tests complete'"],
    "flows": [
        {
            "name": "user-onboarding",
            "steps": [...]
        }
    ]
}

Top-Level Fields

Field Type Required Description
projectName string No Name of the project
baseUrl string Yes Base URL for all requests
beforeRun string[] No Hook: shell commands to run before tests start
afterRun string[] No Hook: shell commands to run after tests complete
flows array Yes Array of flow objects

Flow Object

Field Type Required Description
name string Yes Unique identifier for the flow
steps array Yes Ordered array of step objects

Step Object

Field Type Required Description
name string Yes Unique identifier within the flow
request object Yes HTTP request configuration
assert object Yes Assertions to validate the response
exports object No Variables to extract from the response
options object No Step-level options

Request Object

Field Type Required Description
method string Yes HTTP method (GET, POST, PUT, PATCH, DELETE, OPTIONS, HEAD)
path string Yes Request path (appended to baseUrl)
json object No JSON request body
xml string No XML request body (alternative to json)
files object No File uploads (map of fieldName to relative file path)
headers object No Custom HTTP headers (map of header name to value)
disableHeaders boolean No If true, disables automatic cookie handling

Assert Object

Field Type Required Description
status integer Yes Expected HTTP status code
all array No Array of assertion objects (all must pass)

Assertion Object

Field Type Required Description
jsonpath string No* JSONPath expression to evaluate (for JSON responses)
xpath string No* XPath expression to evaluate (for XML responses)
exists boolean No Assert the path exists (true) or doesn't exist (false)
equals string No Assert the value equals this string
isNot string No Assert the value does NOT equal this string
contains string No Assert the value contains this substring

*Either jsonpath or xpath is required. The appropriate one is used based on the response Content-Type.

Exports Object

A map of variable names to JSONPath or XPath expressions:

{
    "user_id": "$.data.user.id",
    "token": "$.data.token"
}

For XML responses, use XPath:

{
    "user_id": "/response/data/user/id",
    "token": "/response/data/token"
}

Step Options

Field Type Description
timeout string Request timeout (e.g., "5s", "100ms", "1m"). Default: 30s

CLI Reference

Global Flags

These flags work with all commands:

Flag Short Description
--config Config file path (default: veriflow.json)
--json-output Output machine-readable JSON
--no-color Disable colored output
--non-interactive Disable interactive prompts
--verbose -v Enable verbose output
--silent Suppress all output except errors

The NO_COLOR environment variable is also respected.

veriflow init

Creates a new veriflow.json configuration file.

veriflow init

# Anything can be non interactive with required flags
veriflow init --base-url "https://base.com" --non-interactive

veriflow run

Run flows defined in the configuration.

Flag Description
--base-url Override the baseUrl from config
--skip Skip specific flows or steps (repeatable)
--keep-going Continue running even if tests fail
--show-full-error-response Display entire server response payload on error
--show-hooks Print stdout/stderr from beforeRun and afterRun hooks
--skip-hooks Skip executing beforeRun and afterRun hooks
--show-server-responses View responses sent from the server on every request

Examples:

# Run all flows
veriflow run

# Run specific flow(s)
veriflow run user-onboarding checkout

# Run a specific step
veriflow run user-onboarding/register

# Mixed targets. Specific flows with specific steps
veriflow run user-onboarding checkout/payment

# Run veriflow against a specific config
veriflow run --config veriflow-configs/seeding-flows.json

# Override base URL
veriflow run --base-url http://staging.example.com

# Skip specific tests
veriflow run --skip user-onboarding/register --skip checkout

# Continue on failures
veriflow run --keep-going

# CI mode
veriflow run --json-output --no-color --non-interactive

veriflow export

Export flows or steps to external request formats (e.g., curl commands) for inspection or manual execution.

Flag Description
--to Export format (currently only "curl" supported)
--out Write output to file instead of stdout
--base-url Override the baseUrl from config

Output format:

  • Single target: outputs raw curl command
  • Multiple targets: outputs JSON array with stepName and curl fields

Note: Bindings like {{RUN_ID}}, {{bind:var}}, etc. are NOT resolved and will appear as-is in the exported output. Exports capture the request structure but not runtime state (cookies, auth tokens, etc.).

Examples:

# Export entire flow as curl commands
veriflow export user-onboarding

# Export specific step
veriflow export user-onboarding/register

# Export multiple targets (outputs JSON array)
veriflow export user-onboarding checkout/payment

# Export to file
veriflow export user-onboarding --out requests.json

# Override base URL
veriflow export user-onboarding --base-url http://staging.example.com

# Explicit format (curl is default)
veriflow export --to curl user-onboarding

# Export step with file upload
veriflow export user-onboarding/upload-avatar
# Output: curl -X 'POST' 'https://api.example.com/users/avatar' -F 'avatar=@test-files/avatar.jpg'

veriflow flow add

Add a new flow to the configuration.

# Interactive
veriflow flow add

# With name
veriflow flow add user-onboarding
Flag Description
--no-save Modify config in memory only (don't write to disk)

veriflow flow delete

Delete a flow from the configuration.

# Interactive
veriflow flow delete

# With name
veriflow flow delete user-onboarding
Flag Short Description
--yes -y Skip confirmation prompt
--no-save Modify config in memory only

veriflow step add

Add a new step to a flow.

# Interactive
veriflow step add

# With name
veriflow step add register

# Fully specified (for scripts/CI)
veriflow step add register \
  --flow user-onboarding \
  --method POST \
  --path /auth/register \
  --json '{"email": "test@example.com"}' \
  --status 201 \
  --assert "exists $.data.id" \
  --assert "equals $.data.email test@example.com" \
  --assert "isNot $.data.stats PENDING" \
  --export "user_id $.data.id" \
  --non-interactive

# With file upload
veriflow step add upload-avatar \
  --flow user-onboarding \
  --method POST \
  --path /users/avatar \
  --file "avatar:test-files/avatar.jpg" \
  --status 200

# With custom headers
veriflow step add protected-endpoint \
  --flow user-onboarding \
  --method GET \
  --path /api/protected \
  --header "Authorization:Bearer token123" \
  --header "X-API-Key:secret" \
  --status 200
Flag Description
--flow Flow this step belongs to
--method HTTP method
--path Request path
--json JSON body (mutually exclusive with --xml and --file)
--xml XML body (mutually exclusive with --json and --file)
--file File upload (format: fieldName:path, mutually exclusive with --json and --xml, repeatable for multiple files)
--header Custom HTTP header (format: Header-Name:value, repeatable)
--status Expected HTTP status code
--assert Assertion expression (repeatable)
--export Export expression (repeatable)
--no-save Modify config in memory only

Note on file uploads:

  • File paths are relative to the config file location (veriflow.json)
  • Files must be under 100MB in size
  • Multiple files can be uploaded: --file "doc:file1.pdf" --file "image:file2.jpg"
  • MIME types are auto-detected from file extensions

Assertion syntax (supports both JSONPath and XPath):

exists <path>
equals <path> <value>
isNot  <path> <value>
contains <path> <value>

Where <path> is either:

  • JSONPath: $.data.user.id
  • XPath: /response/data/user/id

Export syntax:

<varname> <path>

Examples:

# JSON API
veriflow step add get-user \
  --flow users \
  --method GET \
  --path /api/users/1 \
  --status 200 \
  --assert "exists $.data.id" \
  --assert "equals $.data.name John" \
  --export "user_id $.data.id"

# XML API
veriflow step add get-user-xml \
  --flow users \
  --method GET \
  --path /api/users/1 \
  --status 200 \
  --assert "exists /user/id" \
  --assert "equals /user/name John" \
  --export "user_id /user/id"

# XML request
veriflow step add create-user \
  --flow users \
  --method POST \
  --path /api/users \
  --xml '<user><name>John</name></user>' \
  --status 201

Bindings

Bindings are template variables that get replaced at runtime. They can be used in request bodies, paths, and assertion values.

Bindings can be referenced and used from a different flow but they have to be defined first.

Built-in Bindings

Binding Description
{{RUN_ID}} Unique identifier for the current test run
{{RAND_DIGIT}} Random single digit (0-9)

Example:

{
    "email": "test-{{RUN_ID}}@example.com",
    "code": "{{RAND_DIGIT}}{{RAND_DIGIT}}{{RAND_DIGIT}}{{RAND_DIGIT}}"
}

User-Defined Bindings (Exports)

Use {{bind:variable_name}} to reference exported values from previous steps:

{
    "name": "register",
    "exports": {
        "user_id": "$.data.id"
    }
}
{
    "name": "get-user",
    "request": {
        "path": "/users/{{bind:user_id}}"
    }
}

Bindings are case-sensitive. {{bind:user_id}} and {{bind:User_Id}} are different.

Hooks

Hooks are shell commands that run before and after your test suite.

{
    "beforeRun": ["docker-compose up -d", "sleep 2"],
    "afterRun": ["docker-compose down"]
}
  • beforeRun: Executes before any tests run (e.g., start services, seed database)
  • afterRun: Executes after all tests complete (e.g., cleanup)

Commands run in order. If a beforeRun command fails, tests do not run.

Use --skip-hooks to skip hook execution, or --show-hooks to see their output.

Session Handling

Veriflow automatically maintains cookies across steps within a run. This enables stateful flows like:

  1. Login (receives session cookie)
  2. Protected action (cookie sent automatically)
  3. Logout

To disable automatic cookie handling for a specific step, set disableHeaders: true in the request.

Exit Codes

Code Meaning
0 All tests passed
1 One or more assertions failed
Non-zero Configuration or runtime error

Contributing

Feel free to suggest improvements, start a discussion, file an issue, or open a PR.

License

This project is licensed under the MIT license - see the LICENSE file for details.