7.2 The typed spec and the string DSL (two inputs, one stored form)

A pipeline can be written two ways. Both are accepted as input; the runtime canonicalizes to the typed spec and stores that. You author in whichever reads better; you read back typed.

The typed spec

The structured form — a JSON object with a mode and an array of steps:

{
  "mode": "serial",
  "onFail": "stop",
  "steps": [
    { "call": { "method": "GET", "url": "/data/orders/${id}" }, "as": "$order" },
    { "if": "$order.status == 'open'",
      "call": { "method": "POST", "url": "/payments/charge", "effect": "keyed" },
      "try": true },
    { "transform": { "total": "$sum($order.lines.price)", "charged": "$_ok" } }
  ]
}

This is exactly what the runtime stores and what ?$plan shows. It's the form to reach for when a step needs fields the DSL can't express compactly (an explicit effect, headers, nested joins).

The string DSL

The terse form carried over from Restspace v1 — a JSON array, one string per step:

[
  "GET /data/orders/${id} :$order",
  "try if ($order.status == 'open') POST /payments/charge",
  { "total": "$sum($order.lines.price)", "charged": "$_ok" }
]

It's accepted anywhere a spec is (the envelope's pipeline field, rs2 migrate) and converted on the way in. For straight-line call/condition/capture flows it's markedly more readable, which is why it's often the better authoring choice.

DSL element kinds

Element Meaning
Leading mode token "serial", "parallel", "conditional", "tee", "teeWait" — optionally with fail/succeed actions ("serial stop end"). Only counts as the first element
Step string try? if (cond)? METHOD url ( :$var | :name)?
JSON object a transform (JSONata template)
Nested array a subpipeline
"jsonSplit" a splitter step
"jsonObject" a joiner

Step-string anatomy, in order: optional try, optional if (condition), then METHOD url, then an optional suffix — :$var to capture the result into a variable, or :name to name the step (used by parallel/join). zip, unzip, and multipart are not supported in v1.

Equivalence

The two examples above are the same pipeline. The DSL's :$order becomes the typed "as": "$order"; try if (…) becomes "try": true + "if": "…"; a bare object is a transform; a nested array is a pipeline step. After writing in the DSL, run ?$plan to see the typed form the runtime produced (7.8).

The next sections work through what steps can do — first the step kinds, then the modes that combine them.


Previous: 7.1 The pipeline service · Manual home · Next: 7.3 Step kinds →