Skip to main content

Module script

Module script 

Source
Expand description

The pre_request and post_request hooks: compiling them, running them, and the closed surface a script can see.

§What a script is

A script is Rhai source, written inline in the request file as a YAML block scalar:

method: POST
url: https://api.example.com/orders
pre_request: |
  request.headers["X-Request-Id"] = "abc-123";
post_request: |
  if response.status != 201 {
    throw "expected 201, got " + response.status;
  }

Rhai rather than an embedded JavaScript engine because the whole point of the feature is that a script needs nothing installed next to sendra: the interpreter is linked into the binary, there is no FFI boundary, and the sandbox is a property of what the Engine was built with rather than of a separate runtime’s flags.

§Script source is never substituted

A {{variable}} or ${OS_VAR} inside a script is not expanded. It is whatever those characters mean to Rhai — in practice, part of a string literal. Environment::apply copies both script fields through verbatim, and there is a test on exactly that.

This is a decision, not an oversight. Substitution is textual, and the whole reason it is confined to values is that a value must not be able to change the structure of the document it sits in. A script is structure: it is executable code, so the failure mode is not a malformed URL but a variable whose contents get parsed as program text. A script that needs an environment value reads it off the request it is handed — request.url and request.headers arrive fully substituted — which is both safe and the honest place for it to come from.

§Ordering

Fixed, and stated here because it decides what an existing file means:

  1. Environment substitution.
  2. Config apply.
  3. pre_request, against the fully-substituted, config-applied request. It is the last thing to touch the request before it goes over the wire, so a header it removes stays removed — which is why the CLI applies the config itself and then calls send_prepared rather than send, whose whole job is to apply it.
  4. Send.
  5. post_request, against the response.
  6. Assertions, against the same response, unaffected by whether a post_request script ran or what it decided.

Scripts and assertions are two independent mechanisms that happen to look at the same response. Neither can see the other.

§Both scripts are compiled before the request is sent

Scripts::compile compiles pre_request and post_request up front, so a syntax error in a post_request script is found before the POST that would have created an order — not after. A file whose script does not parse is a broken file in the same way a collection with two identically-named requests is a broken file, and Collection already makes the argument: finding that out before the first request goes over the wire beats finding it out halfway through a run.

It is compiled per request rather than for the whole file, in the same place and for the same reason substitution is per request: a script that will not compile is that request’s problem, not its siblings’.

Structs§

Script
A script that has been parsed and is ready to run.
ScriptOutput
Anything a script printed while it ran, in the order it printed it.
Scripts
A request’s two scripts, both compiled.

Enums§

Hook
Which of the two hooks a script is.
ScriptOutcome
What a post_request script decided about a response.

Functions§

run_post_request
Run a post_request script against a response, returning its verdict and anything it printed.
run_pre_request
Run a pre_request script and return the request it left behind, along with anything it printed.