Appearance
Script reference
Everything a script can reach.
This is Sendwire's scripting surface — the objects available inside a pre-request or post-response script. It is not a web API: Sendwire has no server and exposes no HTTP endpoints of its own.
Everything below is available bare as well — response works exactly as sw.response does — so a pasted snippet usually runs unchanged.
There is no pm
Importing a Postman collection rewrites pm to sw automatically. Type it anyway and the editor underlines it before you run anything; run it anyway and you get an error naming the sw equivalent.
sw.response
Only available in a post-response script. There is no response before the request has been sent.
code | Status code, as a number. 200 |
status | Status text. "OK" |
responseTime | Total milliseconds. |
size | Body size in bytes. |
text() | The body, unparsed. |
json() | The body parsed as JSON. Throws if it is not. |
xml() | The body as a plain object. |
soapBody() | Inside <soap:Body>, as an object. |
xmlValue(name) | The text of the first element with that local name. |
xmlValues(name) | The text of every element with that local name. |
soapFault() | The fault as an object, or null. |
headers.get(name) | One header, case-insensitively. |
headers.has(name) | Whether it is present. |
headers.all() | Every header, as { key, value }. |
connection | Address, port, reuse, ALPN. |
certificate | The leaf certificate the server presented. |
js
sw.test("the order was created", () => {
sw.expect(sw.response.code).to.equal(201)
sw.expect(sw.response.json().status).to.equal("active")
sw.expect(sw.response.headers.get("content-type")).to.include("json")
})Namespace prefixes are ignored by the XML helpers, so soapBody().return works whether the server wrote <return> or <ns2:return>.
sw.environment
The active environment. Values set here are visible to every later request as {{name}}, and are written to your workspace.
get(key) | The value, or undefined. |
set(key, value) | Store it. Non-strings are stringified. |
unset(key) | Remove it. |
has(key) | Whether it is set. |
toObject() | Everything, as a plain object. |
sw.globals and sw.collectionVariables are the same object under different names, so Postman scripts that use them keep working.
js
// Capture it in one request
sw.environment.set("token", sw.response.json().data.token)
// Spend it in the next
// Authorization: Bearer {{token}}
sw.environment.get("token")
sw.environment.has("token")
sw.environment.unset("token")sw.variables
Reading, plus one thing environment cannot do.
get(key) | The value. |
set(key, value) | Same as environment.set. |
has(key) | Whether it is set. |
replaceIn(text) | Substitute every {{name}} in a string. |
replaceIn is how you reach the dynamic values:
js
sw.environment.set("nonce", sw.variables.replaceIn("{{$guid}}"))
sw.environment.set("sentAt", sw.variables.replaceIn("{{$isoTimestamp}}"))sw.request
The request about to be sent. Only useful in a pre-request script — afterwards it has already gone.
js
sw.request.headers.upsert({
key: "X-Signature",
value: sw.crypto.hmacSha256(sw.environment.get("apiSecret"), "message")
})upsert replaces any header of the same name rather than adding a second one.
sw.test and sw.expect
js
sw.test("name", () => {
sw.expect(actual).to.equal(expected)
})Each test is one line in the Scripts tab, and one assertion in a suite run or a CI report. A test that throws fails; a test that returns passes.
The matchers, all of which chain through .to, .be and .not:
.equal(x) | Strictly equal. |
.eql(x) | Deeply equal. |
.above(n) / .below(n) | Greater / less than. |
.least(n) / .most(n) | At least / at most. |
.include(x) | Substring, array member, or subset of an object. |
.match(re) | Matches a regular expression. |
.property(key) | Has that own property. |
.a(type) | "string", "number", "array", "object", "null" … |
.lengthOf(n) | Has that length. |
.ok | Truthy. |
.null | Exactly null. |
js
sw.expect(sw.response.responseTime).to.be.below(500)
sw.expect(sw.response.json().items).to.have.lengthOf(2)
sw.expect(sw.response.json().name).to.not.equal("")sw.crypto
Signing, hashing and nonces, without pulling in a library.
hmacSha256(key, message) | Hex. |
hmacSha256Base64(key, message) | Base64. |
hmacSha1Base64(key, message) | Base64. Some older APIs still want this. |
sha256(message) | Hex. |
md5(message) | Hex. Checksums only — not for anything security-bearing. |
base64(text) | Encode. |
randomUUID() | A v4 UUID. |
randomInt(min, max) | Inclusive of both ends. |
nonce(bytes = 16) | Random hex. |
A signed request, in a pre-request script:
js
const stamp = Math.floor(Date.now() / 1000)
const nonce = sw.crypto.nonce()
const signature = sw.crypto.hmacSha256(
sw.environment.get("apiSecret"),
`${stamp}\n${nonce}\nPOST\n/v1/orders`
)
sw.request.headers.upsert({ key: "X-Signature", value: signature })
sw.request.headers.upsert({ key: "X-Timestamp", value: String(stamp) })sw.sendRequest
Another request from inside a script — a token fetch before the real call, most often. Pre-request scripts wait for it.
js
sw.sendRequest("https://auth.example.com/token", (error, response) => {
if (error) throw error
sw.environment.set("token", response.json().access_token)
})Or with options, and awaited:
js
const response = await sw.sendRequest({
url: "https://auth.example.com/token",
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ client_id: sw.environment.get("clientId") })
})
sw.environment.set("token", response.json().access_token)There is a limit on how many a single script may send, so a loop that has lost its exit condition stops rather than hammering somebody's API.
sw.console
log, warn, error and info. Output appears in the Scripts tab beside the test results, not in a devtools console you would have to open.
Also available
btoa and atob for base64, and the ordinary JavaScript standard library — JSON, Math, Date, Object, Array, String, RegExp, Promise. It is real JavaScript, so if it runs in JavaScript it runs here.
Not available
No require, no import, no filesystem, no network except sw.sendRequest. Scripts run in a sandbox with a time limit, so an accidental infinite loop fails that request instead of freezing the application.