Scripting Overview
Most checks need no code at all — the declarative [assert] block covers status codes, JSON paths, headers, and timing. When you need real logic, Napper lets you script in the language you already use.
| Language | Extension | Runtime | Guide |
|---|---|---|---|
| JavaScript | .js / .mjs |
Node.js 18+ | JavaScript Scripting |
| Python | .py |
Python 3.9+ | Python Scripting |
| F# | .fsx |
.NET 10 SDK | F# Scripting |
| C# | .csx |
.NET 10 SDK | C# Scripting |
There is no "preferred" language. Use whatever your team already tests with. .fsx and .csx happen to be genuinely lovely — concise, strongly typed, immutable by default — but they are never required.
One surface, every language (spec: script-context, script-runner)
Every language sees the same two objects:
ctx— the request/response context for pre/post hooks:ctx.vars,ctx.request,ctx.response,ctx.set(...),ctx.fail(...),ctx.log(...).nap— the orchestration runner for script-driven flows:nap.run(...),nap.runList(...),nap.vars,nap.fail(...).
The same post-script in four languages:
// validate-user.js
import { ctx } from "napper";
const user = ctx.response.json;
if (user.id !== ctx.vars.userId) ctx.fail("User ID mismatch");
ctx.set("token", user.sessionToken);
# validate_user.py
from napper import ctx
user = ctx.response.json
if user["id"] != ctx.vars["userId"]:
ctx.fail("User ID mismatch")
ctx.set("token", user["sessionToken"])
// validate-user.fsx
let user = ctx.Response.Json
if user.GetProperty("id").GetString() <> ctx.Vars["userId"] then ctx.Fail "User ID mismatch"
ctx.Set "token" (user.GetProperty("sessionToken").GetString())
// validate-user.csx
var user = ctx.Response.Json;
if (user.GetProperty("id").GetString() != ctx.Vars["userId"]) ctx.Fail("User ID mismatch");
ctx.Set("token", user.GetProperty("sessionToken").GetString());
Real runtimes, no sandbox
Unlike the sandboxed JavaScript in Postman and Bruno, Napper scripts run on real runtimes — Node.js, Python 3, or .NET — with full access to npm, PyPI, and NuGet. Parse XML, call a database, generate a JWT, validate a schema, or pull in any package.
How to reference a script (spec: nap-file, script-dispatch)
Reference scripts from a .nap file's [script] block, or use a script file as a .naplist step. Dispatch is by extension, so a single playlist can mix languages:
[steps]
./auth/01_login.nap
./scripts/seed-data.js # JavaScript step
./scripts/parametrized-tests.py # Python step
./teardown/cleanup.nap
Zero install (spec: script-sdk)
The Napper binary bundles the JavaScript and Python SDKs and puts them on the runtime's module path, so import { ctx } from "napper" (JS) and from napper import ctx (Python) just work — no npm install, no pip install. The published @nimblesite/napper (npm) and napper (PyPI) packages are conveniences for editor autocomplete and explicit vendoring.
Requirements (spec: script-runtime)
The Napper binary itself is self-contained with no runtime dependencies. Script hooks need the relevant runtime only for the language you actually script in — a JavaScript shop never installs .NET, and a .NET shop never installs Node. See Installation.