API Testing, Supercharged.
Napper is a free, open-source API testing tool for anyone testing APIs. It runs from the command line and edits natively in VS Code, Zed, and any editor via a portable language server.
Define HTTP requests as plain text .nap files, add declarative assertions, chain them into test suites, and run everything in CI/CD with JUnit output.
As simple as curl for quick requests. As powerful as your own code — script in JavaScript, Python, F#, or C#.
VS Code Marketplace · Website · Documentation · Releases
Everything you need for API testing. Nothing you don't.
- CLI First (
cli-run) — The command line is the product. Run requests, execute test suites, and integrate with CI/CD pipelines from your terminal. Napper ships as a self-contained native binary — not a .NET DLL — with zero runtime dependencies. - Editor-Native, LSP-Powered (
vscode-extension,lsp) — First-class extensions for VS Code and Zed, plus a portable language server that brings completions, diagnostics, and hover to any editor. Syntax highlighting (vscode-syntax), request explorer (vscode-explorer), environment switching (vscode-env-switcher), and Test Explorer integration (vscode-test-explorer). Never leave your editor. - Script in Any Language (
script-js,script-py,script-fsx,script-csx) — Write pre/post hooks and orchestration in JavaScript, Python, F#, or C# — whatever your team already runs. Real runtimes (Node.js, Python 3, .NET), full ecosystem access (npm, PyPI, NuGet), no sandbox..fsxand.csxare genuinely lovely, but never required. - Declarative Assertions (
nap-assert) — Assert on status codes (assert-status), JSON paths (assert-equals,assert-exists), headers (assert-contains), and response times (assert-lt) with a clean, readable syntax. No scripting required for simple checks. - Composable Playlists (
naplist-file) — Chain requests into test suites with.naplistfiles. Nest playlists (naplist-nested), reference folders (naplist-folder-step), pass variables between steps (naplist-var-scope). - OpenAPI Import (
openapi-generate) — Generate test files from any OpenAPI spec. Point it at a file, and Napper creates.napfiles with requests, headers, bodies, and assertions. Optionally enhance with AI via GitHub Copilot (vscode-openapi-ai). - Plain Text, Git Friendly (
nap-file) — Every request is a.napfile. Every environment is a.napenvfile (env-file). Version control everything. No binary blobs, no lock-in.
Install from the marketplace in one command:
code --install-extension nimblesite.napperOr search "Napper" in the VS Code Extensions panel (Ctrl+Shift+X / Cmd+Shift+X) and click Install.
To install a specific .vsix manually: open the Extensions panel → ... menu → Install from VSIX....
Requirements: VS Code 1.95.0 or later. The extension shells out to the CLI, so install the CLI binary too.
The CLI is a self-contained binary with no runtime dependencies.
| Platform | Download |
|---|---|
| macOS (Apple Silicon) | napper-osx-arm64 |
| macOS (Intel) | napper-osx-x64 |
| Linux (x64) | napper-linux-x64 |
| Windows (x64) | napper-win-x64.exe |
macOS / Linux:
chmod +x napper-osx-arm64
mv napper-osx-arm64 /usr/local/bin/napper
napper --versionInstall script (macOS / Linux):
curl -fsSL https://raw.githubusercontent.com/Nimblesite/napper/main/scripts/install.sh | bashInstall script (Windows PowerShell):
irm https://raw.githubusercontent.com/Nimblesite/napper/main/scripts/install.ps1 | iexBuild from source (requires .NET SDK + make):
git clone https://github.com/Nimblesite/napper.git && cd napper && make install-binariesNote: Script hooks need a runtime only for the language you write in — JavaScript (
.js) needs Node.js 18+, Python (.py) needs Python 3.9+, and F# (.fsx) / C# (.csx) need the .NET 10 SDK. Plain.napand.naplistfiles need nothing extra. The JS and Python SDKs are bundled — nonpm install/pip installrequired.
See the full installation guide for VSIX manual install, troubleshooting, and macOS Gatekeeper notes.
A .nap file can be as simple as one line:
GET https://httpbin.org/get
[request]
POST {{baseUrl}}/posts
[request.headers]
Content-Type = application/json
Accept = application/json
[request.body]
"""
{
"title": "Nap Integration Test",
"body": "This post was created by the Nap API testing tool",
"userId": {{userId}}
}
"""
[assert]
status = 201
body.id exists
body.title = Nap Integration Test
body.userId = {{userId}}
[meta]
name = Get user by ID
description = Fetches a single user and asserts shape
tags = users, smoke
[vars]
userId = 42
[request]
GET https://api.example.com/users/{{userId}}
[request.headers]
Authorization = Bearer {{token}}
Accept = application/json
[assert]
status = 200
body.id = {{userId}}
body.name exists
headers.Content-Type contains "json"
duration < 500ms
[script]
pre = ./scripts/auth.fsx
post = ./scripts/validate-user.fsx
# Run a single request
napper run ./health.nap
# Run a full test suite
napper run ./smoke.naplist
# With environment + JUnit output
napper run ./tests/ --env staging --output junit| Extension | Spec ID | Purpose | Example |
|---|---|---|---|
.nap |
nap-file |
Single HTTP request with optional assertions and scripts | get-users.nap |
.naplist |
naplist-file |
Ordered playlist of steps (requests, scripts, nested playlists) | smoke.naplist |
.napenv |
env-base |
Environment variables (base config, checked into git) | .napenv |
.napenv.local |
env-local |
Local secrets (gitignored) | .napenv.local |
.napenv.<name> |
env-named |
Named environment | .napenv.staging |
.js / .mjs |
script-js |
JavaScript scripts (Node.js) for pre/post hooks and orchestration | setup.js |
.py |
script-py |
Python scripts (Python 3) for pre/post hooks and orchestration | setup.py |
.fsx |
script-fsx |
F# scripts for pre/post hooks and orchestration | setup.fsx |
.csx |
script-csx |
C# scripts for pre/post hooks and orchestration | setup.csx |
[meta]
name = JSONPlaceholder CRUD
description = Full create-read-update-delete lifecycle for posts
[steps]
../scripts/setup.fsx
./01_get-posts.nap
./02_get-post-by-id.nap
./03_create-post.nap
./04_update-post.nap
./05_patch-post.nap
./06_delete-post.nap
../scripts/teardown.fsx
.napenv (base, checked into git):
baseUrl = https://jsonplaceholder.typicode.com
userId = 1
postId = 1
.napenv.local (secrets, gitignored):
token = eyJhbGci...
apiKey = sk-secret-key
Select a named environment with --env:
napper run ./smoke.naplist --env stagingVariable priority (highest wins):
--var key=valueCLI flags (cli-var).napenv.local(env-local).napenv.<name>named environment (env-named).napenvbase (env-base)[vars]in.nap/.naplistfiles (nap-vars)
Generate .nap test files automatically from any OpenAPI or Swagger spec. Napper creates one file per operation, a .naplist playlist, and a .napenv environment file — giving you a working test suite in seconds.
Supported formats: OpenAPI 3.0.x, OpenAPI 3.1.x, Swagger 2.0 (JSON input).
# Generate from a local spec file
napper generate openapi ./petstore.json --output-dir ./tests
# Output a JSON summary for scripting
napper generate openapi ./spec.json --output-dir ./tests --output jsonOpen the Command Palette (Ctrl+Shift+P / Cmd+Shift+P) and choose:
- Napper: Import OpenAPI from URL — paste a URL (e.g.
https://petstore3.swagger.io/api/v3/openapi.json). Napper downloads the spec and generates files. - Napper: Import OpenAPI from File — browse to a local
.jsonspec file.
Both commands prompt for an output folder and offer basic or AI-enhanced generation.
Endpoints are grouped into subdirectories by API tag:
tests/
├── pets/
│ ├── get-pets.nap
│ ├── post-pets.nap
│ └── get-pets-petId.nap
├── store/
│ └── get-store-inventory.nap
├── petstore.naplist
└── .napenv
Each .nap file includes the method, URL (with path params as {{variables}}), auth headers, request body (from schema), and status code assertions. The .napenv file contains the base URL from the spec's servers field and variable placeholders for auth tokens.
With GitHub Copilot available, choose AI-enhanced generation to get:
- Semantic assertions beyond status codes (e.g.
body.email contains @) - Realistic test data in request bodies instead of placeholder values
- Logical playlist ordering (auth first, then CRUD in dependency order)
Falls back to basic generation automatically if Copilot is unavailable.
See the full OpenAPI import guide for authentication handling, $ref resolution, customisation tips, and troubleshooting.
Usage:
napper run <file|folder> Run a .nap file, .naplist playlist, or folder (cli-run)
napper check <file> Validate a .nap or .naplist file (cli-check)
napper generate openapi <spec> --output-dir <dir> Generate .nap files from OpenAPI spec (cli-generate)
napper help Show this help
Options:
--env <name> Environment name (loads .napenv.<name>) (cli-env)
--var <key=value> Variable override (repeatable) (cli-var)
--output <format> Output: pretty, junit, json, ndjson (cli-output)
--output-dir <dir> Output directory for generate command (cli-output-dir)
--version Print the installed CLI version
--verbose Enable debug-level logging (cli-verbose)
| Exit Code | Meaning |
|---|---|
| 0 | All assertions passed |
| 1 | One or more assertions failed |
| 2 | Runtime error (network, script error, parse error) |
| Feature | Napper | Postman | Bruno | .http files |
|---|---|---|---|---|
| CLI-first design | Yes | No | GUI-first | No CLI |
| Editor integration | VS Code, Zed & LSP | Separate app | Separate app | VS Code only |
| Git-friendly files | Yes | JSON blobs | Yes | Yes |
| OpenAPI import | URL + file + AI | Import only | Import only | No |
| Assertions | Declarative + scripts | JS scripts | JS scripts | None |
| Full scripting language | JS, Python, F#, C# | Sandboxed JS | Sandboxed JS | None |
| CI/CD output formats | JUnit, JSON, NDJSON | Via Newman | Via CLI | None |
| Test Explorer | Native | No | No | No |
| Free & open source | Yes | Freemium | Yes | Yes |
| No account required | Yes | Account needed | Yes | Yes |
my-api/
├── .napenv # Base variables (checked in)
├── .napenv.local # Secrets (gitignored)
├── .napenv.staging # Staging environment
├── auth/
│ ├── 01_login.nap
│ └── 02_refresh-token.nap
├── users/
│ ├── 01_get-user.nap
│ ├── 02_create-user.nap
│ └── 03_delete-user.nap
├── scripts/
│ ├── setup.fsx
│ ├── setup.csx
│ └── teardown.fsx
└── smoke.naplist
MIT
