github unkn0wn-root/resterm v1.4.0

2 hours ago

v1.4.0

This release adds first class HTTP polling and retries, along with clearer RestermScript conditions using the new in and not in operators.

New

Polling and retries

HTTP requests can now be repeated until a condition is met:

### Wait for a job to finish
# @poll every=500ms timeout=30s until=response.json().status == "completed"
GET {{base.url}}/jobs/{{job.id}}

The first request is sent immediately. Resterm then waits between attempts until the condition becomes true or the polling timeout is reached.

Requests can also be retried after network errors, attempt timeouts, or selected HTTP responses:

### Fetch a temporarily unavailable service
# @retry count=4
# @retry-when response.statusCode in [429, 502, 503]
# @retry-backoff exponential(100ms, 2s) jitter=20%
GET {{base.url}}/service

count=4 means four retries after the initial request, for a maximum of five attempts.

Without @retry-when, Resterm retries network errors and attempt timeouts only. A condition can be added when specific HTTP responses should also be retried.

Polling and retries can be combined:

### Wait for a job with transient-error handling
# @retry count=4
# @retry-when response.statusCode in [429, 502, 503]
# @retry-backoff exponential(100ms, 2s) jitter=20%
# @poll every=500ms timeout=30s until=response.json().status == "completed"
GET {{base.url}}/jobs/{{job.id}}

Each polling cycle receives its own retry budget. This allows temporary failures to be handled without prematurely stopping a longer polling operation.

Valid Retry-After response headers are respected when they require a longer delay than the configured backoff.

in and not in expressions

response.statusCode in [200, 201, 204]
response.statusCode not in [400, 404, 500]

"json" in response.header("Content-Type")
"request_id" in response.json()

The operators work with:

  • Lists, where values are compared for equality.
  • Strings, where substring membership is checked.
  • Dictionaries, where exact, case-sensitive keys are checked.

The existing contains(container, value) function remains available. The new expression:

value in container

is equivalent to:

contains(container, value)

in is contextual rather than a reserved word, so existing variables and object properties named in continue to work.

Improved behavior

  • The TUI shows progress while a request is polling or retrying.
  • Request assertions, captures, and response test scripts run only after the final response.
  • Repeated attempts appear as one logical history entry.
  • Reported duration includes attempts and time spent waiting.
  • Request bodies are buffered and replayed safely between attempts.
  • Dynamic request values, such as generated UUIDs and timestamps, remain stable across attempts.
  • Retry exhaustion and polling timeouts produce clear errors.
  • Invalid Retry-After headers are ignored with a warning instead of failing the request.

Notes

Polling and retries apply to regular HTTP requests. They are not supported for gRPC, SSE, or WebSocket requests and cannot be combined with @profile. Take care when retrying operations with side effects, such as POST requests. A server may accept an attempt even if the client does not receive its response.

Don't miss a new resterm release

NewReleases is sending notifications on new releases.