roas-arazzo-executor
Executes OpenAPI Arazzo workflows: runs every step's request, follows the description's success and failure actions, and reports what happened.
An Arazzo description is a program: ordered steps that call API operations, assert on the responses, name outputs, and branch on success or failure. roas-arazzo parses and validates one; this crate runs it.
Quick start
use Description;
use ;
#
workflow `buyPet` succeeded
- findPet GET https://api.example.com/v1/pets/7 → 200
- orderPet POST https://api.example.com/v1/pets/7/order → 201
orderId = "o-1"
petName = "fluffy"
It performs no IO of its own
The engine decides what to send and asks a client to send it. That is what lets one engine serve a blocking caller, an async one, and a test with no network at all:
| Entry point | Client trait | Waiting |
|---|---|---|
execute |
HttpClient |
std::thread::sleep |
execute_async |
AsyncHttpClient |
the client's own sleep |
Run |
none — you drive it | you decide |
Client (behind the reqwest feature) implements both, over reqwest::blocking::Client and reqwest::Client. Implement the trait yourself to reuse your own client, authentication or middleware.
Source descriptions are the same story: fetching them is IO, so the caller passes the parsed documents to Options::source. roas-file-fetcher and roas-http-fetcher do that job for the loader and do it here just as well.
Testing a workflow
testing::Fake answers from a script and keeps what it was asked, so a workflow can be tested without a server:
use ;
use json;
#
Driving Run directly goes one step further: Progress::Wait hands back the delay a retry asked for instead of spending it, so retry behaviour can be asserted in microseconds. One request is outstanding at a time — advance refuses to hand out another until supply has answered the first, so a driving loop cannot send the same request twice.
What it runs
- Steps that name an operation by
operationId(bare, or$sourceDescriptions.<name>.<id>) or byoperationPath, and steps that call anotherworkflowId. - Parameters in
path,query,querystring,headerandcookie, from the workflow and the step, with$components.parametersreferences and theirvalueoverrides. - Request bodies, with runtime expressions anywhere inside the payload and
replacementsby JSON Pointer or JSONPath. - Criteria —
simpleconditions (comparisons,&&,||, parentheses; string comparisons are case-insensitive and numeric strings coerce, as the specification requires),regex, andjsonpath, each with{$expressions}filled in before the engine that reads them sees them. Ajsonpathcondition passes on a non-empty nodelist, whatever the node holds. - Actions —
end,gotoa step or a workflow, andretry, which honoursretryAfter, defaults to a single attempt whenretryLimitis absent, may send the run through another step or workflow before trying again, and gives way to the next failure action once its limit is spent. - Outputs at step and workflow level, including
Selectors, readable by later steps as$steps.<id>.outputs.<name>. - Runtime expressions —
$url,$method,$statusCode,$request.*,$response.*,$inputs,$outputs,$steps,$workflows.<id>.inputs/.outputs,$sourceDescriptions,$components, and$self. dependsOnbetween steps and between workflows, which orders them and rejects circles — as does reading another step's outputs, which orders the two without anyone having to say so.
A step that calls a workflow is a step like any other: what it called becomes its outputs, its own outputs are named on top, its successCriteria are judged, its timeout covers the whole call, and its onSuccess / onFailure decide where the workflow goes next. It gets a record of its own in the report — Performed::Workflow rather than Performed::Request.
Both Arazzo versions: v1.1 directly, and v1.0 through execute_v1_0 (the v1_0 feature), which upconverts first so there is one interpreter.
What it does not run
Each of these is reported where it is met, never passed over — a run should not look successful because something was skipped.
- AsyncAPI steps (
channelPath/action/correlationId): they need a broker client, not an HTTP one. - XPath criteria and selectors: JSON Pointer and JSONPath are supported.
inputsschema validation: inputs are passed through as given.- Parallel execution:
dependsOnorders steps and workflows; they still run one at a time.
Safety rails
A description can loop — goto is a jump. Options caps the number of steps (1000), the depth of workflow calls (8) and the retries of one step (10); each raises ExecutionError::Limit rather than running forever.
License
MIT OR Apache-2.0, as the rest of the workspace.