Classic Scenario Recipes
Combine concepts and scripting into real-world workflows. Each scenario gives: goal → flow → scripts you can paste straight into the UI → expected result. All script logic has been verified end-to-end in the real app.
- Scenario 1: login for token, auto-attach for the whole group
- Scenario 2: AES-encrypt the request body, decrypt the response (multi-script chain)
- Scenario 3: extract · assert · dynamic variables · signing
- Scenario 4: reuse shared logic with library scripts and
require()
Examples use the local test server (
/oauth2/token,/protected,/echo,/json, etc.). Swap in your own paths and Pre-URLs when pointing at your own APIs.
Scenario 1: Login for Token, Auto-Attach for the Whole Group
Goal: call the login API, store the token, and have every subsequent request attach it automatically — no manual copying.
Request A — login (post-response script stores the token)
POST /oauth2/token, form body: grant_type=password&username=qruser&password=qrpass&client_id=qr-client&client_secret=qr-secret
Add one script step to the post-response chain:
async function onResponse(context, url, response) {
var j = response.body.parseJSON();
if (j && j.access_token) {
sdk.env.set('authToken', j.access_token); // store on the runtime blackboard
sdk.env.set('tokenType', j.token_type || 'Bearer');
}
return response;
}
Request B — attach the token (the same script can be copied to every authorized API)
GET /protected, add one script step to the pre-send chain:
async function onRequest(context, url, request) {
var tok = sdk.env.get('authToken'); // take from the blackboard
var ty = sdk.env.get('tokenType') || 'Bearer';
if (tok) { request.headers.set('Authorization', ty + ' ' + tok); }
return request;
}
Expected result
| Action | Result |
|---|---|
| Send A first (login) | 200, response contains access_token, token stored |
| Then send B (attach) | 200, response {authorized:true, ...} |
| Disable scripts, send B again | 401 (pre-send chain doesn't run → no token injected — proof the script is what attaches it) |
Key: A and B must be in the same group bound to the same environment (runtime variables are scoped per environment), and path fragments are completed by the environment Pre-URL.
Scenario 2: AES-Encrypt the Request Body, Decrypt the Response (Multi-Script Chain)
Goal: AES-encrypt the body before sending (only ciphertext on the wire), decrypt the response after it arrives; also demonstrates chaining multiple scripts and sharing data between them.
Why can it be split into multiple scripts? Scripts in the same chain share
globalThis: script ① stashes the keys/plaintext, scripts ②③ pick them up. Each script stays single-purpose and can be toggled independently.
Pre-send chain
Script ① (prepare context and keys):
async function onRequest(context, url, request) {
globalThis.__traceId = $uuid.v4();
globalThis.__aesKey = '0123456789abcdef'; // 16 bytes → AES-128
globalThis.__aesIv = 'abcdef0123456789';
globalThis.__plain = request.body.parseText();
request.headers.set('X-Trace-Id', globalThis.__traceId);
return request;
}
Script ② (encrypt the body):
async function onRequest(context, url, request) {
var cipher = $crypto.encryptAES(globalThis.__plain, globalThis.__aesKey, globalThis.__aesIv);
request.body = cipher; // only ciphertext on the wire
request.headers.set('X-Encrypt', 'AES-128-CBC');
return request;
}
(Optional) script ③ adds the token-attach logic from Scenario 1.
Post-response chain (decrypt + rewrite the response)
async function onResponse(context, url, response) {
var j = response.body.parseJSON();
var cipher = j && j.body && j.body.utf8; // /echo echoes the request body in body.utf8
var recovered = cipher ? $crypto.decryptAES(cipher, globalThis.__aesKey, globalThis.__aesIv) : '';
var obj = null; try { obj = JSON.parse(recovered); } catch (e) {}
response.body = JSON.stringify({
traceId: globalThis.__traceId, decrypted: recovered,
roundtripOk: recovered === globalThis.__plain, jsonValid: !!obj,
});
return response;
}
Request body (before encryption): {"order":123,"note":"secret-payload","amount":99.5}
Expected result
After sending you get:
{"traceId":"...","decrypted":"{\"order\":123,\"note\":\"secret-payload\",\"amount\":99.5}","roundtripOk":true,"jsonValid":true}
roundtripOk:true: the decrypted result matches the original plaintext byte for byte- The rewritten response body is visible in the result (proof the post-response rewrite took effect)
⚠️
$cryptoarguments are positional strings; on failure it only returns a string starting withError:— it does not throw or abort (verified: bad ciphertext →Invalid ciphertext, wrong key/iv →CryptoKit error). Chinese / non-ASCII plaintext encrypts and decrypts correctly (the old claim that "non-ASCII aborts" has been disproven). If you need to write a decrypted result into an HTTP header, make sure the value is ASCII (header values reject non-ASCII, otherwise aTypeErroris thrown); put UTF-8 content in the body or query params instead.
Scenario 3: Extract · Assert · Dynamic Variables · Signing
A set of lightweight automations — most need no JS at all, using declarative extract / assert steps.
3.1 Pass a response field to the next request (extract)
- Add an extract step to request A's post-response chain: variable
author, sourceresponse body JSON, expression$.slideshow.author. - Add a script step to request B's pre-send chain:
var v=sdk.env.get('author'); if(v){ request.headers.set('X-Extracted', v); } return request;
Verified: request B's /echo echoes an X-Extracted header matching the author in request A's response.
3.2 Assertions
Add assert steps to the post-response chain: status code = 200, $.slideshow.title exists. Results are listed one by one (pass/fail, expected vs actual).
3.3 Dynamic variables
Write them directly in params / headers / URL:
GET /echo?ts={{$timestamp}}&r={{$randomInt}}&u={{$uuid}}
Verified: every send echoes ts as the current timestamp, r as a different random integer, and u as a valid UUID. Full list: concepts, dynamic variables.
3.4 Signing (MD5, standard and interoperable)
Many open APIs sign with MD5(param concatenation + secret). Use the verified-standard $hash.md5:
async function onRequest(context, url, request) {
var appId = sdk.env.get('appId');
var secret = sdk.env.get('appSecret'); // keep secrets in environment variables
var ts = String(Math.floor(Date.now() / 1000));
var sign = $hash.md5(appId + ts + secret); // concatenation order per your backend's convention
request.queries.set('appId', appId);
request.queries.set('ts', ts);
request.queries.set('sign', sign);
return request;
}
Verified: $hash.md5('abc') = 900150983cd24fb0d6963f7d28e17f72, matching the backend.
✅ The native
$hmac($hmac.sha256(message, key)etc.) has been vector-by-vector verified to match standard RFC HMAC (note the argument order: data first, key second) and can be used for external signing; the$hashfamily is standard too. Only$jwtdegrades object payloads into[object Object](stringify first withJSON.stringify, or sign on the server).
Scenario 4: Reuse Shared Logic with Library Scripts and require()
Goal: extract "inject token", "unified signing" and "logging" into reusable units — reference them in many places, maintain them in one.
Two ways to reuse:
- Library script step: a full script with its own
onRequest/onResponse— add it as a step and it runs in order, sharingglobalThiswith the other steps. require(): save pure functions in a script library withmodule.exports, then load them from any script — best for signing helpers, codecs and other shared utilities:
// script library "sign-lib" (no entry function needed)
function sign(method, path, body, secret) {
return $hmac.sha256(method + path + body, secret);
}
module.exports = { sign };
// any request script
async function onRequest(context, url, request) {
const { sign } = require('@libs/sign-lib');
request.headers.set('X-Sign', sign('POST', request.path, request.body.parseText(), sdk.env.get('appSecret')));
return request;
}
Use Copy require statement in the library manager for the stable identifier form. Built-in libs (@libs/base64, @libs/hex) are available everywhere without setup. Full mechanics: scripting, Require Script Libraries.
Scenario Cheat Sheet
| I want to… | Which steps |
|---|---|
| Auto-attach the token on every API after login | Post-response script stores + pre-send script reads and injects the header |
| Encrypt the request body / decrypt the response | Pre-send $crypto.encryptAES + post-response decryptAES |
| Pass a response field to the next request | Extract step + script reading the variable |
| Validate status codes / fields | Assert step |
| Generate random values / timestamps each send | Dynamic variables like {{$uuid}} |
| Sign an open API | $hash.md5(...) (standard) |
| Reuse the same logic in many places | Library script, or require('@libs/<key>') a script library |