Recipes

Polling Status Flow

Exports, report generation, payment confirmation: the client kicks off a job and polls until it finishes. A static mock cannot exercise that UI, because the status never changes. This recipe counts the polls with a flag and walks the job through its lifecycle.

The recipe

mock "GET /exports/{id}" {
format = "json"
body = <<-EOF
{{= $key (append 'exports:' request.params.id ':polls')}}
{{= $count (toInt (default (getFlag $key) 0))}}
{{setFlag $key (add $count 1)}}
{{#lt $count 2}}
{ "id": {{request.params.id}}, "status": "queued" }
{{else lt $count 5}}
{ "id": {{request.params.id}}, "status": "processing" }
{{else}}
{
"id": {{request.params.id}},
"status": "done",
"url": "https://files.example.com/export-{{request.params.id}}.csv"
}
{{/lt}}
EOF
}

Try it

$curl http://localhost:8080/exports/7
{ "id": 7, "status": "queued" }

Keep polling: requests three through five report processing, and from the sixth on the export is done with a download URL.

How it works

  • Each job id gets its own counter flag, exports:<id>:polls, so two jobs polled in parallel advance independently.
  • default (getFlag $key) 0 makes the first poll start from zero, and setFlag increments before the branching, one count per request.
  • The lt chain with {{else lt ...}} maps count ranges to lifecycle stages. Widen the ranges to make the job feel slower.
The counter is state, so the job stays done forever once finished. Reset it to run the flow again: delete the flag in the flags panel, or add the reset mock below.
mock "DELETE /exports/{id}/polls" {
format = "json"
body = <<-EOF
{{delFlag (append 'exports:' request.params.id ':polls')}}
{ "reset": true }
EOF
}

Variations

  • Self-resetting jobs: pass a TTL as setFlag's third argument, {{setFlag $key (add $count 1) 60000}}, and an untouched job forgets its progress after a minute.
  • Failure endings: add an {{else}} stage that returns status: "failed" for counts past a threshold, or roll random into the final branch for a chance of failure, as in Simulate Slow or Unstable APIs.
  • Time-based instead of poll-based: store a timestamp on the first poll and branch on dateDiff so the job finishes after real seconds rather than a number of requests.