Salta ai contenuti

Scenarios

Questi contenuti non sono ancora disponibili nella tua lingua.

Scenarios let a single _routes entry return different responses depending on the incoming request. A _scenarios array defines the conditions; the first match wins. _otherwise is the explicit fallback when none match.

This is how you mock a real login flow, simulate role-based access, or inject errors for specific inputs — all directly in db.yml, with no handler code.


_routes:
- _method: POST
_path: /auth/login
_scenarios:
- _when:
body.email: ana@company.com
body.password: secret123
_response:
_status: 200
_body:
token: tok-ana-abc
role: admin
_otherwise:
_status: 401
_body:
error: Invalid credentials
  • _scenarios is an array evaluated in declaration order — the first match wins.
  • _when defines the conditions the request must satisfy.
  • _otherwise is the response returned when no scenario matched. If _otherwise is absent and no scenario matches, yRest falls back to the top-level _response block.

When _when is a YAML mapping, all entries must match (AND logic):

_routes:
- _method: POST
_path: /auth/login
_scenarios:
- _when:
body.email: ana@company.com
body.password: secret123
_response:
_status: 200
_body: { token: tok-ana, role: admin }
_otherwise:
_status: 401
_body: { error: Invalid credentials }

The scenario above only fires when both body.email equals ana@company.com and body.password equals secret123. Sending the correct email but the wrong password hits _otherwise.


When _when is a YAML sequence, any group can match (OR of ANDs). Each item in the array is itself an AND group:

_routes:
- _method: GET
_path: /admin/dashboard
_scenarios:
- _when:
- { headers.x-user-role: admin }
- { headers.x-user-role: superadmin }
- { headers.x-user-role: manager }
_response:
_status: 200
_body:
section: dashboard
access: granted
_otherwise:
_status: 403
_body: { error: Insufficient permissions }

Each item in the _when array is evaluated independently. If any group matches, the scenario fires.

You can mix multi-field AND groups inside the OR array:

_routes:
- _method: POST
_path: /payments/refund
_scenarios:
- _when:
- { body.reason: duplicate, body.status: pending }
- { body.reason: fraud }
_response:
_status: 200
_body:
refundId: "{{uuid}}"
status: approved
processedAt: "{{now}}"
_otherwise:
_status: 422
_body:
error: Refund not eligible
reason: "{{body.reason}}"

The first group — reason: duplicate AND status: pending — is one AND block. The second — reason: fraud — is another. Either match triggers the refund approval.


Conditions use dot-notation to access parts of the request:

Key prefixAccesses
body.XField X from the parsed JSON request body
params.XPath parameter :X from the URL
query.XQuery string value for key X
headers.XRequest header value for key X (lowercase name)
_routes:
# Condition on a path param
- _method: GET
_path: /users/:id/profile
_scenarios:
- _when:
params.id: "1"
_response:
_status: 200
_body: { id: 1, name: Ana, role: admin, plan: pro }
_otherwise:
_status: 200
_body: { id: "{{params.id}}", name: Generic User, role: viewer, plan: free }
# Condition on a query string value
- _method: GET
_path: /invoices
_scenarios:
- _when:
query.status: overdue
_response:
_status: 200
_body:
- { id: 1, amount: 1200.00, dueDate: "2026-01-15", status: overdue }
- { id: 4, amount: 450.00, dueDate: "2026-02-01", status: overdue }
_otherwise:
_status: 200
_body: []

Condition keys support the same operator suffixes as query parameters. Append the suffix to the dot-notation key:

SuffixDescriptionExample
_gteGreater than or equal (numeric/string)body.amount_gte: 100
_lteLess than or equal (numeric/string)body.amount_lte: 500
_neNot equalbody.status_ne: cancelled
_likeCase-insensitive substring matchbody.email_like: "@company.com"
_startCase-insensitive prefix matchbody.coupon_start: PROMO
_regexCase-insensitive regex matchbody.phone_regex: "^\\+1"
_routes:
- _method: POST
_path: /checkout
_scenarios:
# Block suspicious large orders
- _when:
body.total_gte: 10000
_response:
_status: 422
_body:
error: Order exceeds limit
maxAllowed: 9999.99
submitted: "{{body.total}}"
# Apply discount for company emails
- _when:
body.email_like: "@company.com"
_response:
_status: 200
_body:
orderId: "{{uuid}}"
discount: 0.15
message: Employee discount applied
processedAt: "{{now}}"
_otherwise:
_status: 200
_body:
orderId: "{{uuid}}"
discount: 0
processedAt: "{{now}}"

_otherwise runs when _scenarios is defined but no scenario matched. It is more explicit than _response because it signals that something was evaluated but no branch triggered:

_routes:
- _method: DELETE
_path: /users/:id
_scenarios:
- _when:
headers.x-confirm-delete: "yes"
_response:
_status: 200
_body:
deleted: true
userId: "{{params.id}}"
deletedAt: "{{now}}"
_otherwise:
_status: 400
_body:
error: Delete not confirmed
hint: Set the X-Confirm-Delete header to "yes"

If _otherwise is absent and no scenario matches, yRest falls back to the top-level _response block. If that is also absent, it returns 200 with a null body.


_delay adds simulated latency (in milliseconds) before any response — including _otherwise and _error responses:

_routes:
- _method: POST
_path: /auth/login
_delay: 600
_scenarios:
- _when:
body.email: ana@company.com
body.password: secret123
_response:
_status: 200
_body: { token: tok-ana-abc, expiresIn: 3600 }
_otherwise:
_status: 401
_body: { error: Invalid credentials }

Every request to POST /auth/login waits 600 ms before a response is sent, regardless of which branch resolves the reply.


Use _status inside a scenario _response to return an error for specific conditions:

_routes:
- _method: POST
_path: /payments/charge
_scenarios:
- _when:
body.cardNumber: "4000-0000-0000-0002"
_response:
_status: 402
_body:
error: Card declined
code: INSUFFICIENT_FUNDS
cardLast4: "0002"
- _when:
body.cardNumber: "4000-0000-0000-0119"
_response:
_status: 402
_body:
error: Card declined
code: STOLEN_CARD
cardLast4: "0119"
_otherwise:
_status: 200
_body:
chargeId: "{{uuid}}"
status: approved
amount: "{{body.amount}}"
processedAt: "{{now}}"

This is different from the top-level _error key — that key always forces an error regardless of the request. Scenario-based errors only fire when the _when condition matches.


All {{variable}} template variables work inside _response._body and _otherwise._body within scenarios:

_routes:
- _method: POST
_path: /support/ticket
_scenarios:
- _when:
body.priority: urgent
_response:
_status: 201
_body:
ticketId: "{{uuid}}"
priority: urgent
assignedTo: on-call-team
eta: 30 minutes
createdAt: "{{now}}"
submittedBy: "{{body.email}}"
_otherwise:
_status: 201
_body:
ticketId: "{{uuid}}"
priority: normal
assignedTo: support-queue
eta: 2 business days
createdAt: "{{now}}"
submittedBy: "{{body.email}}"

See Template Variables for the full list of available variables.


KeyTypeDescription
_scenariosarray of scenario objectsList of conditional branches, evaluated in declaration order
_whenobject (AND) or array of objects (OR)Conditions to evaluate against the request
_response{ _status?, _body?, _headers? }Response to return when this scenario’s _when matches
_otherwise{ _status?, _body?, _headers? }Response when _scenarios is defined but none matched
_delayinteger (ms)Per-route latency applied before any response

_when condition keys:

PatternMatches
body.XField X in the parsed request body
body.X.YNested field (X.Y) in the request body
params.XPath parameter :X
query.XQuery string value for key X
headers.XRequest header (use lowercase header name)
body.X_gteField X >= value (numeric or lexicographic)
body.X_lteField X <= value
body.X_neField X ≠ value
body.X_likeField X contains value (case-insensitive)
body.X_startField X starts with value (case-insensitive)
body.X_regexField X matches regex (case-insensitive)

Support several test accounts with distinct roles, each returning its own token:

_routes:
- _method: POST
_path: /auth/login
_delay: 400
_scenarios:
- _when:
body.email: admin@company.com
body.password: adminpass
_response:
_status: 200
_body:
token: tok-admin-xyz789
user: { id: 1, name: Admin User, role: admin }
loginAt: "{{now}}"
- _when:
body.email: editor@company.com
body.password: editorpass
_response:
_status: 200
_body:
token: tok-editor-abc456
user: { id: 2, name: Editor User, role: editor }
loginAt: "{{now}}"
- _when:
body.email_like: "@company.com"
body.password_ne: ""
_response:
_status: 200
_body:
token: tok-generic-aaa111
user: { id: 99, name: Company User, role: viewer }
loginAt: "{{now}}"
_otherwise:
_status: 401
_body:
error: Invalid credentials
email: "{{body.email}}"

Return content based on the role sent in a header:

_routes:
- _method: GET
_path: /billing/invoices
_scenarios:
- _when:
- { headers.x-user-role: admin }
- { headers.x-user-role: billing }
_response:
_status: 200
_body:
invoices:
- { id: 1, amount: 1200.00, status: paid }
- { id: 2, amount: 450.00, status: pending }
total: 2
- _when:
headers.x-user-role: viewer
_response:
_status: 403
_body:
error: Read-only users cannot access billing
role: viewer
_otherwise:
_status: 401
_body: { error: No role provided }

Test all the card failure scenarios your frontend needs to handle:

_routes:
- _method: POST
_path: /payments/charge
_delay: 1200
_scenarios:
- _when:
body.cardNumber: "4000-0000-0000-0002"
_response:
_status: 402
_body: { error: Card declined, code: INSUFFICIENT_FUNDS }
- _when:
body.cardNumber: "4000-0000-0000-9995"
_response:
_status: 402
_body: { error: Card declined, code: DO_NOT_HONOR }
- _when:
body.amount_gte: 10000
_response:
_status: 422
_body:
error: Amount exceeds single-transaction limit
limit: 9999.99
submitted: "{{body.amount}}"
- _when:
body.currency_ne: USD
_response:
_status: 422
_body:
error: Currency not supported
accepted: [USD]
submitted: "{{body.currency}}"
_otherwise:
_status: 200
_body:
chargeId: "{{uuid}}"
status: approved
amount: "{{body.amount}}"
currency: "{{body.currency}}"
processedAt: "{{now}}"

Accept a few valid codes, reject everything else:

_routes:
- _method: POST
_path: /onboarding/verify-code
_scenarios:
- _when:
- { body.code: BETA2026 }
- { body.code: EARLYBIRD }
- { body.code: PARTNER99 }
_response:
_status: 200
_body:
valid: true
plan: pro
discount: 0.20
activatedAt: "{{now}}"
_otherwise:
_status: 400
_body:
valid: false
error: Invalid or expired invite code
submitted: "{{body.code}}"

  • Template Variables — use {{now}}, {{body.X}} and others in scenario responses
  • Handler Functions — full programmatic control when scenarios aren’t enough
  • Static Routes — the full _routes reference with headers, delay and error injection