docs Request files
Request file anatomy
Separators, comments, directives and bodies in .http and .rest files.
A .http or .rest file holds requests, with a method, URL, headers, and an optional body for each one. Comments can hold directives that name a request, set options, or add tests.
Separators and comments
-
Begin each request with a line that starts with
###. Everything up to the next separator belongs to the same request. -
Lines prefixed with
#,//, or--are treated as comments. Metadata directives live inside these comment blocks. -
A block comment starts with
/*at the beginning of a line and ends at*/. Directives inside it are read like any other comment, and a leading*on each line is skipped, so a/** ... */block with* @name loginlines works. -
A standalone comment whose content starts with
@nameis treated as a directive. -
At file or request scope, an unknown directive is ignored with a warning. A known directive used in the wrong place is handled the same way.
-
Between
@workflowand the next request, an unknown directive is a parse error. This catches mistakes such as@stpethat would otherwise remove a workflow step. Directives attached to requests are still request-scoped, even when a workflow runs those requests. A request directive such as@nameor@grpc-proto, a>script line, or a line of plain text starts the next request, so a later@step,@if, or@switchbefore the request line is a parse error. Blank lines and plain comments keep the workflow open. -
After
@mockand before the response, only@matchand@expectare allowed. Any other directive-shaped comment is a parse error. -
To write a comment that starts like a directive, add another comment marker, for example
## @if .... -
If a directive problem does not make the file invalid, Resterm reports a warning and keeps parsing. For example, it drops an unknown option on
@ssh,@k8s,@sse, or@websocketbut keeps the rest of the directive.If Resterm cannot read a directive at all, such as an
@capturewith no usable scope, it drops the whole directive and reports the problem. Warnings never change the exit code. -
An option may appear only once in a directive. Resterm reports duplicates instead of silently keeping the last value. Repeated
@match jsonand@match json-rulesdeclarations are merged as described in Splitting a long matcher. -
Write options as
key=valuewithout spaces around=. In most directives, a bare key meanstrue, but a bare key for an option that takes a value, such asjitter, is an error. Resterm rejectskey = value,key =value,key= value, and=valuewithout setting the option. This keepspersist = falsefrom enabling persistence by mistake. -
Use
=for regular options:timeout<=1sis an error.@tracelatency budgets also accept<=. -
Quote only the value, as in
cmd="gh auth token". A quoted field such as"timeout=1s"is a plain word and does not settimeout. Directives that accept only options, such as@settings, warn about quoted options. -
An empty value such as
strict_hostkey=is allowed at the end of the line or before anotherkey=valueoption. -
A file or global
@sshor@k8sprofile with spaces around an operator, a missing key, or the wrong operator is unavailable to requests. Requests using an invalid@sshprofile report its name, source line, and underlying error; requests using an invalid@k8sprofile report the profile's error. -
Alternate names count as the same option. For example, you cannot use both
known_hostsandknown-hostson one@sshdirective. Empty values are ignored for regular options, but not for switches.strict_hostkey=enables the switch, so it conflicts withstrict-hostkey=false. -
@comparerequires non-empty values for its baseline and group options. This is stricter than general alias conflict handling:# @ssh host=h known-hosts=a known_hosts=is valid, but# @compare dev stage base=dev baseline=reports an empty baseline. -
Directives that require a value report an error when left empty or given only quotes, such as
@name "".@name,@operation,@grpc-descriptor,@grpc-proto,@grpc-import-path,@grpc-authority, and@grpc-metadatareportvalue missing, while@runand the polling and retry directives name what is missing, such as@retry count is required. Some directives deliberately accept an empty value.@graphqlenables GraphQL,@queryand@variablesread the lines below them, and@grpc-reflectiondefaults to on. -
A request directive that replaces one value may appear only once. This includes
@auth,@name,@timeout,@when,@for-each,@poll,@retry,@trace,@profile,@compare, and the single-value gRPC and GraphQL directives. A second declaration is a parse error; remove it before running the file.A declaration the parser rejects does not count toward this check. A GraphQL directive ignored while GraphQL is off does not count either, but it still produces a warning.
-
Directives such as
@tag,@capture,@assert,@apply,@var,@setting, and@bodyadd to earlier declarations.@graphql,@sse, and@websocketmay repeat becauseoffresets their state. For GraphQL, the reset also clears@operation,@variables, and@query, so they may be declared again after@graphql off. Duplicate directive checks apply only within a request. File directives may repeat because some of them define named profiles. -
Using both
@sseand WebSocket (@websocketor a@wsstep) on one request is a parse error, and so is using@graphql,@sse, or WebSocket on aGRPCrequest line.@graphqlcombines with either@sseor WebSocket. Turning a protocol off, as with@sse off, never conflicts. -
Files can be saved with parse errors. The status line shows the number of errors, for example
Saved requests.http (1 parse error). Requests cannot run until those errors are fixed. -
In the TUI, live editor diagnostics underline offending text and show
ERR <n>/WARN <n>counts beside the status message. PressKin editor normal mode for details on the current line, org ./:diagnosticsfor the complete list. When editor diagnostics are disabled, the existingWARN line <n>segment reports warnings from the last matching parse. Parse warnings also appear in the Explain pane for each run. -
When editor diagnostics are disabled, editing hides the
WARN line <n>segment until the document is parsed again on save, explicit reload, or request execution. -
resterm runlists warnings underWARNin text output, in theWarnings:section of a single-request result, and underwarningsin JSON.
Multiline directives
Some directives can span multiple comment lines. Resterm keeps reading while the directive's expression, matcher, or template is incomplete:
# @assert licensing.assertResponse(
# response,
# expected,
# options
# )- RestermScript expressions continue while an opening
(,[, or{remains unmatched outside a string or comment. This applies to@assert,@when,@skip-if,@capture,@apply,@patch,@for-each,@if,@elif,@switch, and@case. @matchcontinues while a quoted or bracketed option value remains open. See Splitting a long matcher.- Text captures continue while a
{{marker remains open. See Captures. - Continuation lines may use any supported comment marker and do not repeat the directive name. Directives such as
@name,@tag, and@stepremain on one line. - Only the expression can keep a directive open. Names, messages, options, and loop variables do not. Separators such as
=>,run=,as, andinonly count outside strings, comments, and nested groups. - Options and loop variables after the closing delimiter remain part of the directive.
- A new directive, a non-comment line, a request separator, or the end of the file stops collection. Resterm reports an unmatched delimiter at the opening line and drops the incomplete directive.
- Errors inside continued expressions keep their original line and column. Reports and stack frames show the expression on one line.
Metadata directives
| Directive | Syntax | Description |
|---|---|---|
@name |
# @name identifier |
Friendly name used in the navigator, history, and captures. |
@const |
# @const name value |
A constant resolved when the file is loaded. It cannot change and is available to every request in the document. |
@description / @desc |
# @description ... |
Multi-line description. Lines are joined with newlines. |
@tag / @tags |
# @tag smoke billing |
Tags for grouping and filters (comma- or space-separated). |
@trace |
# @trace dns<=40ms total<=200ms tolerance=25ms |
Enable per-phase tracing and optional latency budgets. @trace off turns it off. See Timeline & tracing. |
@no-log / @nolog |
# @no-log |
Prevents the response body snippet from being stored in history. |
@log-sensitive-headers / @log-secret-headers |
# @log-sensitive-headers [true|false] |
Allow allowlisted sensitive headers (Authorization, Proxy-Authorization, and API-token headers such as X-API-Key, X-Access-Token, and X-Auth-Key) to appear in history. Omit it or set it to false to keep them masked, which is the default. |
@setting |
# @setting key value |
Set an HTTP, transport, or TLS option such as timeout, proxy, max-redirects, or max-response-size. |
@settings |
# @settings key1=val1 key2=val2 ... |
Several settings on one line. Supports the same keys as @setting and future prefixes. |
@timeout |
# @timeout 5s |
Equivalent to @setting timeout 5s. |
Body content
- Inline: everything after the blank line that separates headers and body.
- External file:
< ./payloads/create-user.jsonloads the file relative to the request file and sends it as it is. Add# @body expand(or# @body expand-templates) to expand{{...}}templates and@ pathinclude lines in the file first. To also search the workspace root and the current working directory, setRESTERM_ENABLE_FALLBACK=1. - Inline includes: lines in the body starting with
@ path/to/fileare replaced with the file contents (useful for multi-part templates). Only lines written in the body count. A value placed by a template never becomes an include, even when it contains a line that starts with@. - XML/SOAP: inline XML is sent exactly as written after template expansion. XML tags such as
<soap:Envelope>are body text, not file references. - Forced inline body: add
# @body inline(or# @body raw) when a literal body line intentionally looks like a file reference, such as< this is just a string. This only affects parsing. Template expansion and inline includes still work as usual. - Multipart: set
Content-Type: multipart/form-data; boundary=...and write the parts inline. Everything from the first--boundaryline to the closing--boundary--line is body text, so part lines that start with#,//, or--are sent as written instead of being read as comments. Without aboundaryin the header, the boundary lines are still kept, but part lines that start with#or//are read as comments. An@ pathline inside a part is replaced with the file's bytes unchanged, so binary files work. Resterm sends multipart bodies with CRLF line endings. - GraphQL: handled separately (see GraphQL).
A multipart upload with one text field and one file:
### Upload avatar
POST https://example.com/upload
Content-Type: multipart/form-data; boundary=resterm
--resterm
Content-Disposition: form-data; name="title"
Profile photo
--resterm
Content-Disposition: form-data; name="file"; filename="avatar.png"
Content-Type: image/png
@ ./avatar.png
--resterm--