v1.9.0
Run variables let workflow steps share a generated value. The Profile tab compares each profile with the previous run. Expressions and assertions using vars.get now see the value actually sent with the request.
Run variables
When a workflow creates an order and fetches it later, both steps need the same reference. Helpers such as {{$uuid}} and {{$fake.word}} generate a new value each time they are used. With @run var, you can generate the reference once and use it throughout the run.
# @workflow create-order
# @run var suffix = {{$fake.word}}-{{$randomInt(1000, 9999)}}
# @step Create using=CreateOrder
# @step Fetch using=GetOrder
### CreateOrder
# @name CreateOrder
POST https://example.com/orders
Content-Type: application/json
{"reference": "order-{{suffix}}"}
### GetOrder
# @name GetOrder
GET https://example.com/orders/order-{{suffix}}Both steps use the same reference, such as order-amber-2516. The next workflow run generates a new one.
- Workflow variables are set before the first step.
- You can also declare
@run varon a request. Its value is set the first time that request runs in the workflow, then reused by later steps and loop iterations. If the request and workflow use the same name, the request value takes precedence. - Declarations are evaluated in order. A variable can use one declared above it, but not one declared below it. A request variable can build on the workflow value it replaces, as in
# @run var suffix = {{suffix}}-retry. - Use
{{suffix}}in templates, orvars.get("suffix")in scripts, conditions, and loops. Once set, the value is plain text; it is not expanded again. - If a declaration fails, the affected request is not sent. The error identifies the declaration, and the step's
on-failuresetting controls whether later steps run. - Names are case-insensitive and must be unique within a workflow or request.
@run var also works outside workflows. With @for-each, every iteration of a request shares the same value:
### Tag items
# @name tag-items
# @run var batch = {{$randomInt(100, 999)}}
# @for-each ["a", "b", "c"] as item
GET https://example.com/items/{{= item }}?batch={{batch}}This @for-each run sends three HTTP requests. The item changes on each iteration, but all three requests use the same batch value. Sending the request again generates a new batch value.
Run variables are not treated as secrets, so env: references are rejected:
error[parse]: @run var cannot read env: references, use @file or @request
To use an env: reference, put it in @file or @request, then refer to that variable in @run var.
The editor now suggests @run var syntax and completes run variable names. The Explain pane's new Run Variables stage shows which values were set and why any declarations failed.
The example in _examples/workflows.http now uses @run var to share an order reference between steps.
Profile tab
### Benchmark health check
# @profile count=50 warmup=5 delay=100ms
GET https://example.com/healthPROFILE Benchmark health check PASS
dev · 50 measured · 5 warmup · 100ms delay · 11.2s wall
Measured ██████████████████████████████ 50/50
SUCCESS P50 P90 P95 P99 RATE
100% 131ms 158ms 169ms 180ms 4.5/s wall
= +8ms +28ms +27ms +30ms -0.1/s
vs run at 14:02:10 · 50 measured
LATENCY successful measured requests only
118ms-125ms ████████████████████████████████████████ 17 34%
125ms-133ms █████████████████████████████████░░░░░░░ 14 28% p50
133ms-141ms ███████████████████████████████░░░░░░░░░ 13 26%
141ms-149ms ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0 0%
149ms-156ms ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0 0%
156ms-164ms ███░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 1 2%
164ms-172ms ████████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 3 6% p95
172ms-180ms █████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 2 4% p99
min 118ms · mean 133ms · max 180ms · stddev 15ms · active 7.6/s
RESPONSES measured requests
200 ×50
FAILURES
Failures 0 · Warmup warnings 0
- The progress bar tracks warmup and measured requests.
- The summary shows success rate, P50, P90, P95, P99, and request rate.
- The histogram marks P50, P95, and P99.
RESPONSEScounts status codes.FAILURESlists errors and warmup warnings.- The wall rate includes delays between requests; the
activerate counts only time spent in requests.
Latency statistics include only successful measured requests. A measured request fails on a transport error, an HTTP status of 400 or higher, a script error, or a failed test.
If you switch tabs during a run, Resterm keeps your selection. The Pretty, Raw, and Headers tabs show the latest response. On narrow panes, the sections stack vertically.
Compare with the previous run
Each profile is compared with the previous completed run of the same request, in the same environment, with the same delay. The row below the summary shows the changes; the next line shows when the earlier run took place.
- Slower latency, a lower success rate, and a lower request rate are highlighted as warnings. Improvements use the success color.
- Changes below 5% are left uncolored.
- P95 changes are colored only when both runs have at least 20 successful requests; P99 needs 100. With fewer requests, those percentiles reflect the slowest result and make for a poor comparison.
Profile history
- Every profile run is saved to history, even for requests with
@no-log. Profile entries do not store response bodies. - Entries show the result, such as
PASS 10/10, rather than the last HTTP status. - Press
Enteron a profile entry to reopen it in the Profile tab.pstill shows the stored JSON. - History now stores status codes and the first 20 failures. Older entries still open, but they have no failure details or status codes.
Changed
These changes may affect existing request files:
- An unknown or invalid
@profileoption now causes a parse error. No request in the file runs until you fix it. Previously, invalid values silently fell back to defaults. @profileon a gRPC request now causes a parse error.resterm run --profilestill runs gRPC requests once, without profiling.- A failed warmup now produces a warning. It no longer fails the profile or changes the exit code of
resterm run.
In v1.8.2, each of these examples ran 10 times without a warning:
# @profile 5 warmup=1
# @profile cnt=5
# @profile count=0Now each produces an error that identifies the problem:
error[parse]: use count=5 to combine a count with other @profile options
error[parse]: unknown @profile option "cnt"
error[parse]: @profile count must be a positive integer, got "0"
# @profile 50 still works as a short form when no other option is set.
Fixed
In {{= ... }}, @capture, @assert, @poll until=, and @retry-when, vars.get now returns the value actually sent with the request.
### Create order
# @name create
# @request id {{$uuid}}
# @assert response.json().id == vars.get("id")
POST https://example.com/orders
Content-Type: application/json
X-Request-Id: {{= vars.get("id") }}
{"id": "{{id}}"}In v1.8.2, vars.get("id") returned the literal text {{$uuid}}. The header sent that text, and the assertion failed. Now the body, header, and assertion all use the same UUID. vars.id, vars["id"], and vars.require("id") follow the same behavior.
Pre-request scripts still see the declared text because the value is generated only when the request runs.
- A variable that reads itself, such as
# @request a {{= vars.get("a") }}-x, now fails withvariable cycle: a -> abefore the request is sent. Previously, the raw template text was sent in the URL. resterm initnow prepares every file before writing. If a write fails, it removes any files it created and restores files it replaced with-force, instead of leaving a partially written project.