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.
Quickstart Guide
Create your first collection, dispatch HTTP requests, and inspect responses in minutes.
The .bru Format
Understand the human-readable plain text format that makes Git versioning seamless.
Headless CLI Runner
Automate test suites in GitHub Actions or GitLab CI with JUnit XML test reporting.
Scripting & Assertions
Write declarative assertions and sandboxed JavaScript tests with familiar expect() syntax.
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 |
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.brufiles, and addspoppy-clito your system PATH. -
Portable Archive: Download
Poppy-windows-x64.zip. Extract anywhere and launchpoppy.exedirectly. No registry keys or administrative privileges required.
Linux (x64)
Download Poppy-linux-x64.tar.gz and unpack the binaries:
# 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.
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
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.
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
:parameterNamein 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
.protoschema files directly from disk without compilingprotocplugins. - 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-statusand trailer header inspection.
Server-Sent Events (SSE) & LLM Streaming #
Available via Tools → Server-Sent Events...:
- Connects to
text/event-streamfeeds with sub-millisecond timeline logging. - Parses
event,data,id, andretryfields into an interactive event table. - LLM Token Accumulator: Automatically captures and streams OpenAI/ChatGPT/Anthropic style
delta.contentchunks 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):
- Configure your Auth URL, Token URL, Client ID, and Scopes.
- Click Authorize in Browser. Poppy launches your default web browser to the identity provider.
- Upon successful user authentication, the provider redirects to
127.0.0.1:8089/callback. - Poppy intercepts the authorization code, completes the token exchange, extracts
access_tokenandrefresh_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-dateandAuthorization: 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):
- Runtime Variables: Values injected dynamically by pre-request scripts or data fixture loops.
- Folder Variables: Defined in a parent directory's
folder.bru. - Collection Variables: Defined globally in the collection settings.
- Environment Variables: Defined in the currently active
.envfile (e.g.dev.envorprod.env). - 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.envto 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.gitignoreis 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). Whenpoppy-cliruns, 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 {
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: Accessreq.url,req.method, andreq.body.res: In post-response scripts and tests, access:res.getStatus()orres.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 {
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:
username,expectedRole,expectedStatus
ada_lovelace,admin,200
alan_turing,developer,200
anonymous_guest,guest,403
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
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.
Cookie Manager & Persistence (Ctrl+K)
Poppy includes a built-in Netscape-compatible cookie engine:
- Captures and stores cross-request session cookies automatically via
Set-Cookieheaders. - 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
# 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