github unkn0wn-root/resterm v1.0.0

3 hours ago

v1.0.0

After a whole year of building new features and fixing bugs, I'm happy to announce that Resterm is finally going v1!

This release has a few breaking changes, but it also brings many bug fixes and several useful new features (see what's new section).

What v1 means

Until now I have changed things freely, reworking and replacing parts of Resterm as feedback came in and as I found better ways to do things. This release still carries a few of those changes. From v1.0.0 that settles down.

Within the 1.x line:

  • Request file directives keep their names, arguments and meaning.
  • Existing CLI flags keep their meaning.
  • Headless output keeps its JSON field names, JUnit structure and exit codes.
  • Configuration keys (bindings, themes, settings) keep working.
  • The headless Go package keeps its exported API.
  • RestermScript keeps its syntax, builtins and host objects.

Full policy: docs/resterm.md#compatibility

⚠️ Breaking changes

Most of these changes replace ambiguous or inconsistent behavior, but some existing RestermScript files may need small updates.

Environment metadata moved to env.meta

The selected environment name and grouped environment profiles now live under env.meta.

Before:

env.name
env.groups.api

Now:

env.meta.name
env.meta.groups.api

Environment values named name, groups, or meta can still be accessed explicitly:

env.get("name")
env.get("groups")

Use query.fromURL for complete URLs

query.parse now parses raw query text without trying to detect whether the input is a complete URL.

let queryValues = query.parse("page=1&tag=a&tag=b")
let urlValues = query.fromURL("https://example.com/items?page=1")

If you currently pass a complete URL to query.parse, replace it with query.fromURL.

Repeated headers and query parameters are preserved

Request and response dictionaries now preserve repeated values.

A key with one value returns a string, while a key with multiple values returns a list. This is especially useful for headers such as Set-Cookie.

let firstCookie = response.header("Set-Cookie")
let allCookies = response.headers["set-cookie"]

Use header(name) when you only need the first value.

String arguments are now strict

Request mutation methods and header or query helpers no longer automatically convert numbers and booleans to strings.

Use str(...) when a conversion is intentional:

request.setHeader("X-Retry-Count", str(3))
request.setQueryParam("limit", str(25))

Variable resolution is now consistent

Templates, RestermScript, and JavaScript now follow the same variable precedence and name handling rules. Variable names are case-insensitive and surrounding whitespace is ignored. Workflow values and @for-each values also have a clearly defined place in the resolution order.

@const values and process environment variables remain available to regular {{name}} templates, but they are no longer exposed through the script-facing vars object.

An @for-each variable can now shadow a RestermScript namespace or @use alias. For example, naming a loop variable json will hide the json namespace for that request.

What's new

More dynamic data helpers

Resterm can now generate names, email addresses, companies, usernames, phone numbers, random strings, and other useful test data directly inside request files and mock responses.

### Create a random user
POST https://api.example.com/users
Content-Type: application/json

{
  "id": "{{$uuid}}",
  "name": "{{$randomName}}",
  "email": "{{$fake.email}}",
  "company": "{{$fake.company}}",
  "plan": "{{$randomChoice('free', 'pro', 'team')}}",
  "seats": {{$randomInt(1, 25)}},
  "password": "{{$randomString(24)}}"
}

Available helpers include $randomString, $randomChoice, $randomName, $randomEmail, and $fake.* helpers for people, usernames, companies, domains, cities, countries, phone numbers, words, and sentences.

$randomInt can now also generate values from a specific range.

Every reference generates a new value. If you need to reuse the same generated value, save it as a request variable:

# @request trace.id {{$uuid}}
GET https://api.example.com/events/{{trace.id}}
X-Trace-ID: {{trace.id}}

Realistic latency for mock servers

Mock responses can now use random latency distributions instead of always waiting for a fixed amount of time.

# @mock method=GET path=/slow latency=random(100ms,500ms)
# @mock method=GET path=/steady latency=normal(250ms,50ms)
# @mock method=GET path=/jittery latency=jitter(200ms,20%)

This is useful for testing loading states, timeouts, retries, and backoff behavior against less predictable services.

The existing fixed latency syntax still works:

# @mock method=GET path=/slow latency=250ms

Familiar RestermScript operators

RestermScript now supports !, &&, and || in addition to not, and, and or.

export fn shouldSkip(token, offline) {
  return !token || offline
}

export fn isReady(result) {
  return result.ok && result.value.count > 0
}

Both styles have the same behavior, so existing scripts do not need to change.

Better editor completions

Completions can now insert examples such as timeout=5s or latency=random(100ms,500ms) and select the part you will most likely want to change.

Start typing to replace the selected example, or press Tab to keep it. Left and Right can also be used to place the cursor at either side of the inserted value.

The completion details preview can now be toggled with Ctrl+L.

Bug fixes and improvements

  • Multiple pre-request script blocks now share their variables and request changes.
  • request.removeHeader(...) can remove headers declared directly in the request file.
  • Captures run in declaration order, allowing later captures to read earlier ones.
  • Capture changes are saved only when the entire capture batch succeeds.
  • Secret values remain masked after being deleted, overwritten, or involved in a failed script or assertion.
  • Variable lookups now behave consistently between templates, RestermScript, and JavaScript.
  • Nested variable values are resolved correctly before being passed to scripts.
  • Invalid and duplicate header names are reported while parsing the request file.
  • Malformed URL query escapes now produce an error instead of silently dropping parameters.
  • gRPC and GraphQL headers are no longer mistaken for request body content.
  • Quoted authentication values keep their whitespace, including OAuth scopes such as scope="read write".
  • Authentication headers are now detected case-insensitively.
  • Workflow summaries correctly identify the step that failed.
  • RestermScript and metadata colors received a small visual refresh.

A large part of this release also restructures the RestermScript runtime and removes duplicated header, query, URL, and HTTP handling. These changes are mostly invisible during normal use, but they give v1 a cleaner and more reliable foundation.

v1 is an important milestone for me. It does not mean Resterm is finished, but it does mean that I consider its foundations stable and will treat compatibility much more carefully from here.

Thank you to everyone who has tried Resterm, reported bugs, shared feedback, or followed the project during its first year.

Don't miss a new resterm release

NewReleases is sending notifications on new releases.