Overview

Poppy Documentation

Poppy is an ultra-fast, lightweight, offline-first native API testing client and CLI runner built with modern C++20, Qt 6, and libcurl.

Unlike traditional API clients (such as Postman and Insomnia) which bundle heavy Chromium and Node.js runtimes (Electron) that eat hundreds of megabytes of RAM and require cloud logins, Poppy runs as a single, highly-optimized native executable.

Architecture & Performance Benchmarks #

Poppy is engineered from the ground up for extreme developer velocity and low resource consumption.

Metric Postman / Insomnia Bruno Poppy (Native C++/Qt)
Technology Electron (Chromium + Node.js) Electron (Chromium + Node.js) Modern C++20 + Qt 6 + libcurl
Cold Startup Time 2.5s – 5.0s 1.5s – 3.0s < 100 ms (Instantaneous)
Idle RAM Footprint 250 MB – 500 MB 150 MB – 300 MB < 30 MB
Distribution Size 150 MB – 250 MB 100 MB – 180 MB Portable Single Binary
Storage Paradigm Proprietary Cloud Sync Local Filesystem (.bru) 100% Local Filesystem (.bru)
Account / Login Mandatory / Cloud-first Offline-first Zero Tracking / Completely Offline
💡 Why libcurl?

By relying directly on libcurl, Poppy bypasses browser networking stacks, providing exact microsecond DNS/TCP/TLS handshakes, HTTP/2 multiplexing, native proxying (SOCKS5/HTTP), mTLS client certificates, and true protocol fidelity.

Installation & Setup #

Official pre-compiled binaries are published on GitHub for Windows, Linux, and macOS for every release.

Windows (x64)

  • Setup Installer (Recommended): Download Poppy-windows-x64-setup.exe. The setup wizard creates Start Menu entries, Desktop shortcuts, file associations for .bru files, and adds poppy-cli to your system PATH.
  • Portable Archive: Download Poppy-windows-x64.zip. Extract anywhere and launch poppy.exe directly. No registry keys or administrative privileges required.

Linux (x64)

Download Poppy-linux-x64.tar.gz and unpack the binaries:

Bash
# Extract archive
tar -xzf Poppy-linux-x64.tar.gz
cd Poppy-linux-x64

# Run desktop GUI
./poppy

# Or run headless CLI
./poppy-cli --help

macOS (Apple Silicon & Intel)

Download Poppy-macos.dmg, open the image, and drag Poppy.app into your /Applications directory.

Quickstart Guide #

1. Create or Open a Collection

In Poppy, click File → New Collection or press Ctrl+N. Select an empty folder on your hard drive (e.g. ~/api-tests). Poppy will generate a lightweight poppy.json collection descriptor.

2. Add a Request

Right-click your collection or any subfolder in the sidebar, select New Request, enter a name (e.g. Get Users), and pick your HTTP verb (e.g. GET).

3. Configure Parameters & Send

In the top URL bar, type:

https://jsonplaceholder.typicode.com/users

Press Ctrl+Enter or click Send. In under 100 milliseconds, the response viewer will display formatted JSON, status code, latency breakdown, headers, and response size.

Collection Directory Architecture #

Poppy collections map 1-to-1 to ordinary folders on your local disk. There are no hidden binary databases, proprietary exports, or cloud repositories.

Filesystem Layout
my-api-collection/
├── poppy.json                 # Collection name, version, and global metadata
├── environments/
│   ├── dev.env                # Committed environment variables
│   ├── dev.secret.env         # Git-ignored environment secrets (.gitignore)
│   ├── staging.env
│   └── prod.env
├── auth/
│   ├── folder.bru             # Folder-scoped variables and folder settings
│   ├── login.bru              # Bru request file
│   └── refresh-token.bru
└── users/
    ├── list-users.bru
    └── create-user.bru
ℹ️ poppy.json Descriptor

The root poppy.json defines basic collection metadata:

{
  "name": "Acme Commerce API",
  "version": "1.0.0",
  "description": "Public and internal REST endpoints."
}

The .bru File Format #

Poppy is fully compatible with the popular open-source Bru DSL specification. Requests are stored as plain text with clean human-readable blocks.

users/get-user.bru
meta {
  name: Get User Details
  type: http
  seq: 2
}

get {
  url: {{baseUrl}}/api/v1/users/:userId
  body: none
  auth: bearer
}

params:query {
  include_orders: true
  fields: id,name,email
}

params:path {
  userId: 42
}

headers {
  Accept: application/json
  X-Request-Source: poppy-client
}

auth:bearer {
  token: {{authToken}}
}

assertions {
  res.status eq 200
  res.responseTime lt 800
  res.body.id eq 42
  res.body.email contains "@example.com"
}

tests {
  test("Response schema contains required fields", function() {
    var data = res.getBody();
    expect(data).to.have.property('name');
    expect(data.id).to.equal(42);
  });
}

Git Collaboration & Sync #

Because every request, environment, and assertion lives as human-readable plain text, versioning your API tests is as easy as versioning your application source code.

  • Zero Merge Hell: Each request is an isolated file. Developers working on different endpoints never create merge conflicts.
  • Pull Request Reviews: Review API contract changes, assertions, and test scripts directly in GitHub or GitLab PR diffs.
  • Integrated Git Dialog (Ctrl+Shift+G): Inspect working tree branch status, stage collection changes, commit with messages, pull, and push directly from Poppy without switching to an external terminal.

Protocols & Request Types #

REST / HTTP Methods

Poppy supports all HTTP verbs: GET, POST, PUT, DELETE, PATCH, HEAD, and OPTIONS over HTTP/1.1 and HTTP/2.

Path & Query Parameters

  • Path Variables: Use :parameterName in the URL (e.g. /users/:id/orders/:orderId). Poppy automatically binds values from the Params → Path tab.
  • Query Parameters: Manage key-value pairs with individual enable/disable checkboxes and description notes.

Request Body Formats

  • JSON: Real-time syntax highlighting, automatic error flagging with byte offsets, one-click Prettify and Minify.
  • Multipart Form-Data: Send text fields alongside file attachments with automatic MIME type resolution.
  • Form URL-Encoded: Standard key-value encoding for web form endpoints.
  • Raw & Binary: Upload raw strings, XML, HTML, or arbitrary binary files.

GraphQL Split Editor #

Select the GraphQL body tab for a dual-pane editor:

  • Query Pane: Write queries, mutations, and fragments with GraphQL syntax highlighting.
  • Variables Pane: Write JSON variables (e.g. {"limit": 10}) with variable expansion support.
  • Schema Introspection: One-click introspection fetches the remote GraphQL schema for query inspection.

WebSocket Client (ws:// & wss://) #

Native RFC 6455 duplex communication:

  • Interactive handshake with custom headers and protocols.
  • Real-time timeline displaying sent (▲ SENT) and received (▼ RECV) frames.
  • Support for Text, Binary, Ping, and Pong frames with automatic Pong replies.
  • Integrated JSON message inspector with syntax formatting.

gRPC & Protobuf Client #

Native HTTP/2 unary gRPC execution:

  • Proto Parser: Load .proto schema files directly from disk without compiling protoc plugins.
  • Service & Method Selector: Poppy parses packages and lists available services and methods in dropdowns.
  • Automated JSON Template: Generates starter JSON payloads based on proto field definitions.
  • 5-Byte Frame Decoding: Encodes and decodes standard gRPC compression flags and length prefixes with full grpc-status and trailer header inspection.

Server-Sent Events (SSE) & LLM Streaming #

Available via Tools → Server-Sent Events...:

  • Connects to text/event-stream feeds with sub-millisecond timeline logging.
  • Parses event, data, id, and retry fields into an interactive event table.
  • LLM Token Accumulator: Automatically captures and streams OpenAI/ChatGPT/Anthropic style delta.content chunks into a unified live markdown text pane.

Authentication Suite #

Authentication can be configured at the individual request level, or inherited seamlessly from a parent folder or collection.

Bearer, Basic & API Key

  • Bearer Token: Standard Authorization: Bearer <token> with dynamic variable substitution like {{authToken}}.
  • Basic Auth: Username and password, automatically Base64-encoded into Authorization: Basic <credentials>.
  • API Key: Custom key/value pair sent either as a custom Header (e.g. X-API-Key) or Query Parameter.

Interactive OAuth 2.0 Loopback Flow

Poppy features an embedded lightweight OAuth loopback server (running on 127.0.0.1:8089/callback):

  1. Configure your Auth URL, Token URL, Client ID, and Scopes.
  2. Click Authorize in Browser. Poppy launches your default web browser to the identity provider.
  3. Upon successful user authentication, the provider redirects to 127.0.0.1:8089/callback.
  4. Poppy intercepts the authorization code, completes the token exchange, extracts access_token and refresh_token, and automatically injects the Bearer token for subsequent requests.

AWS Signature Version 4 (SigV4)

Native HMAC-SHA256 canonical request signing for Amazon Web Services:

  • Configurable Access Key ID, Secret Access Key, Session Token (for STS), AWS Region, and Service Name (e.g. s3, execute-api).
  • Automatically calculates x-amz-date and Authorization: AWS4-HMAC-SHA256 Credential=... headers.

Mutual TLS (mTLS) & Client Certificates

Authenticate against zero-trust APIs using client SSL certificates (.pem / .crt) and private keys with optional passphrase protection.

Variables & Environments #

Variable Hierarchy & Resolution Precedence

Poppy evaluates variables using a scoped hierarchical lookup. When a variable token like {{baseUrl}} is encountered, Poppy checks scopes in the following order (narrowest to broadest):

  1. Runtime Variables: Values injected dynamically by pre-request scripts or data fixture loops.
  2. Folder Variables: Defined in a parent directory's folder.bru.
  3. Collection Variables: Defined globally in the collection settings.
  4. Environment Variables: Defined in the currently active .env file (e.g. dev.env or prod.env).
  5. Process Environment Variables: Fallback to system environment variables using {{process.env.VARIABLE_NAME}}.

Templating Syntax & Developer Ergonomics

Wrap variable names in double curly brackets: {{variableName}}.

  • URL Bar Autocomplete: Type {{ anywhere in the URL bar to bring up instant autocomplete suggestions showing variable names and current values.
  • Hover Inspection: Hover over any {{variable}} in the URL bar to display an inspection tooltip revealing its resolved value and originating scope.
  • Dynamic Generators: Built-in system variables like {{$guid}}, {{$timestamp}}, and {{$randomInt}}.

Keeping Secrets Safe in Git

Plain text collection files make your API requests and tests versionable and reviewable in the same Pull Request as your application code. Poppy ensures sensitive credentials (API tokens, passwords, private keys) are never leaked into Git:

1. Automatic Dual-File Separation (.env vs .secret.env)

When you configure environment variables, Poppy automatically separates public configuration from private credentials:

  • Shared Configuration (environments/<name>.env): Stores non-secret variables (e.g. BASE_URL=https://api.example.com, API_VERSION=v1). Safe to commit and share with your team.
  • Local Secrets (environments/<name>.secret.env): Variables marked as Secret are stored in an isolated secret file that remains exclusively on your local machine.

2. Automated Git Defense & Pathspec Filtering

  • Auto .gitignore: Poppy automatically appends *.secret.env to your repository's .gitignore.
  • Negative Pathspec Protection: The built-in Git Sync tool explicitly excludes secret files at the Git command line (git add -- . ":(exclude)*.secret.env"), ensuring secrets are never accidentally staged even if .gitignore is missing.
  • UI Masking: The environment editor features an interactive Show / Hide Secrets toggle that masks secret values with bullet dots (••••••••) during presentations or screencasts.

3. CI/CD Environment Variable Overlays (Zero Secrets on Disk)

In automated CI pipelines (GitHub Actions, GitLab CI, Jenkins), your build runners never need physical secret files committed to Git:

  • Automatic Secret Overlay: Commit your environment file with secret variables left empty. In CI, inject matching environment variables (e.g., API_TOKEN). When poppy-cli runs, it automatically binds them to your requests.
  • Direct Process Environment: Use {{process.env.VARIABLE_NAME}} directly in request headers, URLs, or bodies to read runner environment variables with zero configuration.

4. Execution History Redaction

Bearer tokens, passwords, API keys, and AWS Secret Access Keys are automatically redacted before session history is saved to .history.json, preventing accidental commits of past request logs.

Scripting & Assertions Engine #

Declarative Zero-Code Assertions

Declarative assertions allow you to validate response status, latency, headers, and payload values without writing any JavaScript code:

assertions block
assertions {
  res.status eq 200
  res.responseTime lt 500
  res.size lte 20480
  res.header('content-type') contains "application/json"
  res.body.users[0].role eq "admin"
  res.body.error not_contains "unauthorized"
}
Operator Description Example
eq Equal to (numeric or string equality) res.status eq 200
neq Not equal to res.status neq 500
gt / gte Greater than / Greater than or equal to res.body.count gte 1
lt / lte Less than / Less than or equal to res.responseTime lt 1000
contains String contains substring (case-insensitive) res.body.status contains "active"
not_contains String does not contain substring res.body.message not_contains "error"

JavaScript Sandbox (QJSEngine)

Poppy integrates Qt's high-performance QJSEngine ECMAScript runtime. Scripts execute securely in an isolated sandbox with configurable watchdog timeouts (default: 8,000ms) to prevent infinite loops.

poppy & bru API Reference

Both poppy and bru global namespaces expose the same methods:

Method Description
poppy.getEnvVar(name) Retrieves the current value of an environment variable.
poppy.setEnvVar(name, value) Sets or updates an environment variable for subsequent requests.
poppy.getVar(name) Retrieves a scoped runtime or collection variable.
poppy.setVar(name, value) Sets a runtime variable accessible across tests.
poppy.setNextRequest(requestName) Controls collection runner workflow by specifying the next request to execute.
poppy.sleep(milliseconds) Pauses execution synchronously (up to 10,000 ms).

Request & Response Objects

  • req: Access req.url, req.method, and req.body.
  • res: In post-response scripts and tests, access:
    • res.getStatus() or res.status (e.g. 200)
    • res.getBody() (parsed JSON object or raw string)
    • res.getHeader(name)
    • res.responseTime (latency in ms)

Chai / Mocha Style Tests

In the Tests tab, write unit tests using familiar assertion syntax:

tests block
tests {
  test("Status code is 200 OK", function() {
    expect(res.getStatus()).to.equal(200);
  });

  test("User authentication token received", function() {
    var data = res.getBody();
    expect(data).to.have.property("token");
    expect(data.token).to.be.a("string");
    
    // Automatically persist token for subsequent requests
    poppy.setEnvVar("authToken", data.token);
  });
}

Postman pm.* Compatibility Shim

To make migrating existing scripts from Postman frictionless, Poppy includes a built-in pm.* compatibility layer:

// These standard Postman script commands work out-of-the-box:
pm.environment.set("session_id", res.getBody().id);
var currentEnv = pm.environment.get("baseUrl");
pm.variables.set("tempKey", "12345");

CLI Runner & CI/CD Automation #

The standalone poppy-cli binary runs entire collections headlessly inside CI/CD environments with zero GUI dependencies.

Basic Usage

poppy-cli run <path-to-collection-or-bru> [options]
Option Short Default Description
--env <name> -e None Target environment name (e.g. staging maps to environments/staging.env)
--reporter <format> -r cli Output format: cli, json, or junit
--iterations <n> -i 1 Number of consecutive iteration runs to execute
--concurrency <n> -c 1 Number of multithreaded worker threads to run requests concurrently
--delay <ms> — 0 Delay between requests in milliseconds (useful for rate-limiting)
--data <file> -d None Path to CSV or JSON fixture file for data-driven testing
--output <file> -o stdout Save output report directly to a file

Data-Driven Testing (CSV & JSON Fixtures)

Execute your test suite across multiple data rows. Poppy maps each row's columns into {{variable}} placeholders for each cycle:

users.csv
username,expectedRole,expectedStatus
ada_lovelace,admin,200
alan_turing,developer,200
anonymous_guest,guest,403
CLI Command
poppy-cli run ./my-collection --env staging --data ./users.csv

Reporters & JUnit XML

Export standard JUnit XML reports to integrate with CI test dashboards:

poppy-cli run ./my-collection --env ci --reporter junit --output junit-results.xml

GitHub Actions & GitLab CI Recipes

GitHub Actions Workflow

.github/workflows/api-tests.yml
name: API Regression Suite

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Repository
        uses: actions/checkout@v4

      - name: Download Poppy CLI
        run: |
          curl -sL https://github.com/williampepple1/Poppy/releases/latest/download/Poppy-linux-x64.tar.gz | tar -xz
          sudo mv Poppy-linux-x64/poppy-cli /usr/local/bin/

      - name: Run Collection Tests
        env:
          API_SECRET_TOKEN: ${{ secrets.PROD_API_TOKEN }}
        run: |
          poppy-cli run ./tests/api-collection \
            --env production \
            --reporter junit \
            --output test-results.xml

      - name: Publish Test Results
        uses: EnricoMi/publish-unit-test-result-action@v2
        if: always()
        with:
          files: test-results.xml

Advanced Developer Tools #

Embedded Local Mock Server

Simulate backend APIs without writing boilerplate mock code. Accessible via Tools → Mock Server...:

  • Bind to any local port (e.g. 8080, 3000).
  • Configure routes with exact HTTP method, URL path, custom response headers, HTTP status codes, and JSON response bodies.
  • Simulated Latency: Add configurable delay (in ms) to test frontend loading spinners and timeout handling.
  • One-Click Collection Import: Instantly populate mock endpoints from all requests in your active collection.
  • Live Logging: Inspect incoming requests, payloads, and client headers in real time.

Side-by-Side Response Diff Viewer

Compare API responses across environments or revisions via Tools → Response Diff Viewer:

  • Interactive dual-pane visual difference viewer.
  • Synchronized line scrolling, line number alignment, and additions/deletions coloring.
  • Load responses directly from current editor tabs, past execution history, or saved files on disk.

Response Visualizer & Data Grid

Under the response section, switch to the Visualize tab:

  • Interactive Data Grid: Transforms JSON arrays into sortable, filterable tables with column resizing.
  • Bar Chart Generator: Automatically renders comparative bar charts for numeric metrics against text keys.
  • Property Inspector: Visualizes nested objects with key, type, and value inspection.

Poppy includes a built-in Netscape-compatible cookie engine:

  • Captures and stores cross-request session cookies automatically via Set-Cookie headers.
  • Press Ctrl+K to inspect, search, edit, or delete stored cookies by domain and path.
  • The response pane features a dedicated Cookies tab displaying all cookies set by the executed endpoint.

Quick Open Command Palette (Ctrl+P)

Instantly jump to any request in your collection. Press Ctrl+P, start typing, and use arrow keys to navigate. Shows colored HTTP method pills and directory breadcrumbs.

Global Find & Replace (Ctrl+Shift+F)

Search across your entire collection: request names, URLs, headers, request bodies, assertions, and test scripts. Supports case-sensitive matching, regex, and selective or batch replacement.

Interoperability, Migration & Codegen

  • cURL Paste Auto-Detect: Paste any curl ... command directly into the URL bar. Poppy parses method, headers, parameters, and bodies automatically.
  • Postman v2.1: Two-way import and export between Postman collections and Poppy collections.
  • Insomnia v4 & OpenAPI 3.0: Import OpenAPI 3.0 specs into collections or export collections to OpenAPI 3.0 JSON.
  • HTTP Archive (.har): Export collections to HAR format for sharing with web devtools.
  • Multi-Language Code Generation: Export any request with one click to production-ready code in Python, JavaScript (Fetch & Axios), Go, Rust, C#, Java, PHP, Ruby, and C++ (libcurl).

Keyboard Shortcuts Reference #

Shortcut Action
Ctrl+Enter / Cmd+Enter Send current request
Ctrl+P / Cmd+P Quick Open Command Palette (fuzzy switcher)
Ctrl+F / Cmd+F In-response search and JSONPath evaluation
Ctrl+Shift+F Global Find & Replace across collection
Ctrl+Shift+G Open Git Version Control & Sync dialog
Ctrl+K / Cmd+K Open Cookie Jar & Manager dialog
Ctrl+T / Cmd+T Toggle Dark / Light UI theme
Ctrl+S / Cmd+S Save active request to disk
Ctrl+W / Cmd+W Close active tab
Ctrl+N / Cmd+N New request dialog

Building from Source #

Poppy uses CMake and requires a modern C++20 compiler and Qt 6.

Prerequisites

  • CMake (>= 3.20)
  • C++20 Compiler: GCC 11+, Clang 14+, or MSVC 2022+
  • Qt 6: Core, Gui, Widgets, Network, Qml
  • Ninja: Recommended build system
Build Commands
# 1. Clone repository
git clone https://github.com/williampepple1/Poppy.git
cd Poppy

# 2. Configure with CMake
cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Release

# 3. Compile GUI and CLI
cmake --build build

# 4. Run automated test suites (13 suites)
ctest --test-dir build --output-on-failure