github unkn0wn-root/resterm v1.9.0

4 hours ago

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 var on 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, or vars.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-failure setting 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/health
PROFILE  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.
  • RESPONSES counts status codes. FAILURES lists errors and warmup warnings.
  • The wall rate includes delays between requests; the active rate 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 Enter on a profile entry to reopen it in the Profile tab. p still 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 @profile option now causes a parse error. No request in the file runs until you fix it. Previously, invalid values silently fell back to defaults.
  • @profile on a gRPC request now causes a parse error. resterm run --profile still 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=0

Now 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 with variable cycle: a -> a before the request is sent. Previously, the raw template text was sent in the URL.
  • resterm init now 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.

Don't miss a new resterm release

NewReleases is sending notifications on new releases.