Skip to content

Seed recorded API mocks from OpenAPI specs

Wraith’s primary workflow is record -> synthesize -> verify, with no spec required. But when you do have an OpenAPI 3.x spec, you can use it two ways:

  1. Seed: generate a scenario plan from the spec and (optionally) execute it against a live API to produce recordings.
  2. Measure coverage: compare what’s in your recordings to what the spec declares, and surface the gaps.

Both are additive - they complement recording, they don’t replace it. The recorded behaviour still wins for synthesis.

Terminal window
wraith explore --from-openapi petstore.yaml

Parses the spec and prints a scenario plan: a structured list of request sequences that together exercise every operation. No network, no writes - just a plan you can review.

With --against <url>, the plan is executed:

Terminal window
wraith explore --from-openapi petstore.yaml \
--against https://petstore.example.com \
--header "Authorization: Bearer $TOKEN"

Each scenario’s steps are sent via async reqwest. The output reports per-step outcomes (match, mismatch, error) alongside the plan.

FlagDescription
--from-openapiPath to spec (YAML or JSON)
--againstOptional live URL to execute scenarios against
--headerRepeatable "Name: Value" headers for auth
--max-scenariosCap the number of scenarios (safety bound)
--recordCapture executed exchanges as a WREC session (requires --against and --twin)
--twinTwin to record into (twins/<NAME>/recordings/sessions/<run-id>/)
--tagExtra session tags, in addition to the automatic explore + synthetic tags
--formatOutput format: pretty, text, json (auto-detects)
{
"api_title": "Petstore",
"count": 4,
"operations_covered": 3,
"scenarios": [
{
"name": "petstore.pets.crud_lifecycle",
"category": "crud_lifecycle",
"step_count": 3,
"entities": ["pet"],
"priority": 1
}
],
"plan": { "...": "full ScenarioPlan" },
"execution": {
"base_url": "https://petstore.example.com",
"total_steps": 7,
"matched_steps": 5,
"mismatched_steps": 1,
"error_steps": 1,
"results": [
{
"scenario": "petstore.pets.crud_lifecycle",
"steps": [
{ "method": "GET", "path": "/pets/{id}", "expected_status": 200, "observed_status": 200, "outcome": "match" }
]
}
]
},
"advice": [{ "level": "info", "type": "plan-only", "message": "..." }]
}

execution is present only when --against is set.

By default --against does not capture WRECs — it’s a preview / smoke check, useful for “does this spec actually describe the service” or “which operations are live?”

Since v0.17.0, add --record --twin <name> and the executed scenarios are captured as a normal recording session — same scrub-on-write pipeline as wraith record, tagged explore + synthetic for provenance — ready for wraith synth:

Terminal window
# Twin a service from synthetic traffic only (no real data ever touches it)
wraith init myapi --base-url https://staging.example.com
wraith explore --from-openapi spec.yaml \
--against https://staging.example.com \
--record --twin myapi
wraith synth myapi
wraith check myapi

This is the data-safety shortcut: for services where recording real traffic is blocked, drive a safe environment with synthesized requests and twin the shapes. It doesn’t replace real-traffic fidelity — synthesized scenarios exercise the spec’s happy paths, not your production distribution — but it gets a usable twin with zero exposure. For real recordings, wraith record remains the tool:

Terminal window
# 1. Preview: does the spec match reality?
wraith explore --from-openapi petstore.yaml --against https://api.example.com
# 2. Record: capture real traffic for the twin
wraith record myapi --port 8080
# ... exercise the API through the proxy ...
# 3. Cover: which operations from the spec are in the recordings?
wraith coverage myapi --openapi petstore.yaml

Extends the existing coverage command to compute spec-vs-recordings gap.

Terminal window
wraith coverage myapi --openapi petstore.yaml

Walks every recorded session and matches request paths against spec templates (treating {param} as wildcards). Reports what’s covered and what isn’t:

{
"coverage": {
"route_coverage": { "...existing...": "..." },
"state_coverage": null,
"spec_coverage": {
"api_title": "Petstore",
"covered_count": 2,
"total_count": 3,
"percentage": 0.667,
"uncovered_operations": [
{ "method": "GET", "path": "/pets/{id}" }
],
"manifest": { "...": "full CoverageManifest" }
}
},
"advice": [
{ "level": "info", "type": "spec-coverage-primary", "message": "Route coverage reflects synthesized twin; spec coverage reflects the raw API surface in recordings." }
]
}

The pre-existing route_coverage field is unchanged - it reports coverage against the synthesized twin’s routes. The new spec_coverage reports coverage against the raw API surface declared in the spec. They answer different questions:

  • route_coverage asks: how much of my twin is exercised by my tests?
  • spec_coverage asks: how much of the real API surface is in my recordings?

Both are useful; both ship side by side.

  • You have a spec and want a smoke check against a staging or preview deployment before committing to a recording run.
  • You want to quantify your recording coverage (“we have WRECs for 42 of the 68 documented operations, here’s the gap list”).
  • You’re onboarding a new API and want a starting plan for what to exercise.

When not to use it:

  • The spec is aspirational and doesn’t match reality. (Most public specs are.) Record the real traffic; the spec lies. wraith explore --against will surface this quickly.
  • You already have thorough recordings. Nothing to add.

OpenAPI security schemes are surfaced in the plan but wraith doesn’t automatically source credentials - pass them via --header at execution time:

Terminal window
wraith explore --from-openapi stripe.yaml \
--against https://api.stripe.com \
--header "Authorization: Bearer $STRIPE_KEY"

For schemes beyond Bearer / API key (OAuth flows, signed requests), you’ll typically want to record real traffic anyway.