Skip to main content

probeflow

Pytest for HTTP APIs: a local CLI that runs Git-diffable .http request files as an enforceable test suite. No accounts, cloud sync, GUI, or team workspace service.

Overview

probeflow reads IntelliJ / VS Code REST Client request files, executes them, checks explicit response assertions, and fails CI when the contract breaks.

Installation

# From source (recommended for development)
pip install -e ".[dev]"

# Or install from PyPI
pip install probeflow

After installation the probeflow command is available in your PATH.

Quick Start

Create a .http file:

### @name = getUsers
GET https://api.example.com/users
Accept: application/json

###

### @name = createUser
POST https://api.example.com/users
Content-Type: application/json

{
    "name": "Alice",
    "email": "alice@example.com"
}

Run it:

probeflow run requests.http
probeflow test requests.http   # Execute as an enforceable test suite

Commands

probeflow run

Execute requests from a .http file interactively.

probeflow run requests.http                  # Run all requests
probeflow run requests.http --index 0        # Run one request by 0-based index
probeflow run requests.http --env dev        # Use .env.dev for variable substitution
probeflow run requests.http --headers        # Show response headers
probeflow run requests.http --timeout 60     # Set timeout in seconds (default: 30)
probeflow run requests.http --quiet          # Suppress output, show errors only
probeflow run requests.http --check-assertions # Evaluate assertions after each request

Response chaining works in run too — a named request's response is available as {{name.response.body.$.field}} in subsequent requests within the same file. Use --check-assertions to evaluate assertions during development (exit code 1 on failure). For CI-enforced assertions, use test.

probeflow test

Execute requests in declaration order and evaluate every ### @assert block. Exits 0 only when every request completes and every assertion passes.

probeflow test tests/api.http
probeflow test tests/api.http --env staging
probeflow test tests/api.http --json results.json --junit-xml results.xml

probeflow validate

Check a .http file for syntax errors without executing any requests. Request names (### @name = ...) must be unique within a file. Duplicate names produce an error. In test mode, unresolved variables (variables not found in .env files, system environment, or response chains) are treated as errors.

probeflow validate requests.http

probeflow format

Normalize a .http file for consistent style (method casing, header formatting, separator spacing).

probeflow format requests.http               # Format in-place
probeflow format requests.http --check       # Check only — exit 0 if already formatted
probeflow format requests.http -o out.http   # Write to a different file

probeflow version

Show the installed version and implemented grammar version.

probeflow version

GitHub Actions

The test command's non-zero exit status makes a broken API produce a red check:

name: API tests

on: [push, pull_request]

jobs:
  api:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.11"
      - run: pip install -e ".[dev]"
      - name: Run API contract tests
        run: probeflow test tests/api.http --junit-xml api-results.xml

If tests/api.http contains # status == 200 and the API returns 500, the step exits 1 and GitHub marks the workflow with a red X.

.http File Format

probeflow follows the IntelliJ / VS Code REST Client .http file format. All probeflow-specific extensions (### @assert, ### @name, etc.) use constructs that non-probeflow tools treat as comments or separators, so files remain compatible with both editors.

Basic Request

GET https://api.example.com/users

Request with Headers and Body

POST https://api.example.com/users
Content-Type: application/json
Accept: application/json
Authorization: Bearer token123

{
    "name": "Alice",
    "role": "admin"
}

Multiple Requests

Separate requests with ###:

### @name = listUsers
GET https://api.example.com/users

###

### @name = createUser
POST https://api.example.com/users
Content-Type: application/json

{"name": "Bob"}

Named Requests

### @name = healthCheck
GET https://api.example.com/health

Names are used in test output and for response chaining.

Comments

// This is a comment
# This is also a comment
GET https://api.example.com/data

HTTP Version

GET https://api.example.com/data HTTP/1.1

Script Hooks

### @before and ### @after directives point to Python hook functions:

### @name = createResource
### @before = hooks.py:sign_request
POST https://api.example.com/resources
Content-Type: application/json

{"name": "test-resource"}

### @after = hooks.py:verify_signature

Hook references are parsed and validated, but not executed in this release. The test runner refuses files containing hooks rather than running arbitrary code implicitly. A future executor will require an explicit --allow-scripts flag.

Supported Methods

GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS

Assertions

Add a ### @assert block after any request to make probeflow test enforce the response contract:

### @name = getUser
GET https://api.example.com/users/1

### @assert
# status == 200
# body.$.name == "Alice"
# body.$.email is string
# body.$.roles is array
# body.$.address exists
# duration < 500ms
# header.Content-Type contains "application/json"

Assertion Syntax

Target Example
Status code status == 200 · status in [200, 201] · status < 300
Body field body.$.name == "Alice" · body.$.count > 0
Body type body.$.id is number · body.$.tags is array
Body existence body.$.token exists · body.$.error not exists
Body pattern body.$.email matches ".*@example\\.com"
Header header.Content-Type contains "json" · header.X-Id exists
Duration duration < 500ms

Supported Operators

== != < > <= >= in contains matches exists not exists is

Type Names for is

string · number · boolean · array · object

Response Chaining

Use a preceding named request's response as a variable in later requests:

### @name = login
POST https://api.example.com/auth
Content-Type: application/json

{"username": "alice", "password": "{{auth_password}}"}

###

### @name = getProfile
GET https://api.example.com/me
Authorization: Bearer {{login.response.body.$.token}}

### @assert
# status == 200
# body.$.username == "alice"

Chaining Reference Syntax

Reference Resolves to
{{name.response.status}} HTTP status code as a string
{{name.response.body.$.field}} JSONPath value from the response body
{{name.response.headers.X-Request-Id}} Response header value

Chaining references resolve in declaration order. Referencing a request that hasn't run yet, or one that failed, is a hard error with a clear message.

Environment Variables

.env Files

Place a .env file (or .env.<name>) next to your .http file, or in any parent directory. ProbeFlow searches upward from the .http file's directory to find the nearest .env file:

# .env.dev
base_url=https://api.example.com
auth_token=my-secret-token

Variable Substitution

Use {{variable}} syntax in URLs, headers, and bodies:

### @env = dev
GET {{base_url}}/users
Authorization: Bearer {{auth_token}}

Resolution Order

  1. Chaining references ({{name.response.*}}) — resolved from prior responses
  2. .env.<name> file variables (when @env is set)
  3. Default .env / .env.local file variables
  4. System environment variables (os.environ)
  5. Left as-is ({{name}}) — visible in output so you know what's missing

Output

probeflow run displays:

  • Status line color-coded by range — green 2xx, yellow 3xx, red 4xx, bold red 5xx
  • Timing in milliseconds and response size in human-readable bytes
  • JSON syntax highlighting for application/json responses
  • Response headers when --headers is passed

probeflow test displays per-request PASS / FAIL with the first failing assertion message. Use --json or --junit-xml for machine-readable output.

Development

# Install in editable mode with dev dependencies
pip install -e ".[dev]"

# Run the full test suite (coverage included)
python -m pytest

# Lint
ruff check .

# Format
ruff format .

# Check formatting without modifying
ruff format --check .

Project Structure

probeflow/
├── probeflow/
│   ├── __init__.py       # Package metadata and version
│   ├── models.py         # Pydantic data models (AST)
│   ├── parser.py         # .http file lexer + grammar-driven parser
│   ├── client.py         # HTTP client (httpx wrapper)
│   ├── environment.py    # Variable substitution, .env loading, auth helpers
│   ├── evaluator.py      # Assertion evaluation engine
│   ├── formatter.py      # Rich terminal output
│   ├── test_runner.py    # Test suite loop, JUnit/JSON report writers
│   └── cli.py            # Typer CLI — run, test, validate, format, version
├── tests/
│   ├── conftest.py
│   ├── fixtures/          # .http fixture files + golden JSON snapshots
│   ├── test_parser.py
│   ├── test_parser_golden.py
│   ├── test_environment.py
│   ├── test_evaluator.py
│   ├── test_client.py
│   ├── test_cli.py
│   └── test_phase2.py    # Auth, multipart, response chaining
├── examples/
│   ├── simple.http
│   ├── requests.http
│   └── .env.dev
├── docs/
│   └── spec.md           # Formal .http grammar (EBNF)
├── pyproject.toml
└── README.md

License

MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

probeflow-0.2.0.tar.gz (53.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

probeflow-0.2.0-py3-none-any.whl (31.9 kB view details)

Uploaded Python 3

File details

Details for the file probeflow-0.2.0.tar.gz.

File metadata

  • Download URL: probeflow-0.2.0.tar.gz
  • Upload date:
  • Size: 53.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for probeflow-0.2.0.tar.gz
Algorithm Hash digest
SHA256 b0faa75d3cb3c6cdb020a6cc08ee59d06c19288fe88515d3a36af500156e8119
MD5 2f764f18c45969d8f941ac458f3f34dd
BLAKE2b-256 5d2bb9373cb654b7512a295af0bdfe47d7daad6d471c27a88631ed8629165f08

See more details on using hashes here.

Provenance

The following attestation bundles were made for probeflow-0.2.0.tar.gz:

Publisher: release.yml on Kunal241207/probeflow

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file probeflow-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: probeflow-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 31.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for probeflow-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7031fd2915e3a2a9c39f4478e96d5daf92de0d3cf0794c3913cc887728a94c4a
MD5 547f922edf87a824b8136541494a9d30
BLAKE2b-256 223ada28086a348fba074a3eab071207f01db198672a48d4e0a2357252e1fd1c

See more details on using hashes here.

Provenance

The following attestation bundles were made for probeflow-0.2.0-py3-none-any.whl:

Publisher: release.yml on Kunal241207/probeflow

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page