Recipes

Mock One Edge Case

The backend works fine; you just cannot make it produce the case you need. An empty result, a permissions error, a malformed record. This recipe keeps all traffic flowing to the real API and intercepts exactly one branch, using proxying and match precedence.

The recipe

Start Mocko with your real backend as the proxy target, and point your app at Mocko:

$mocko -u https://demo-api.mockoapp.net mocks
mock "GET /posts" {
body = <<-EOF
{{#is request.query.userId 1}}
[]
{{else}}
{{proxy}}
{{/is}}
EOF
}

Try it

This example proxies to a live demo backend, so it runs as-is. User 1 hits the mocked empty state; every other request, on this route or any other, gets the real thing:

$curl 'http://localhost:8080/posts?userId=1'
[]
$curl http://localhost:8080/posts
[ { "id": 1, "userId": 1, "title": "Getting started with mocking" }, { "id": 2, "userId": 2, "title": "Designing good test data" }, { "id": 3, "userId": 2, "title": "Contract testing in practice" } ]

How it works

  • The mock owns the whole GET /posts route, but only the userId=1 branch renders a mocked response. Every other request falls into the {{proxy}} branch and is forwarded with its original method, path, query, headers, and body.
  • Routes with no mock at all never reach a template: the proxy URL from -u handles them directly.
  • {{proxy}}halts the template, so the backend's response is returned exactly as received.

Variations

One resource misbehaves. Exact paths beat parameterized ones, and mocked routes beat the proxy fallback, so you can break a single record while all others stay real:

mock "GET /posts/99" {
status = 500
format = "json"
body = <<-EOF
{ "error": "Internal server error" }
EOF
}

Opt in with a request header. Let the mock stay dormant until a client asks for the scenario, which is great on shared instances where other people use the same routes:

mock "GET /posts/{id}" {
body = <<-EOF
{{#is request.headers.x-scenario 'deleted'}}
{{setStatus 410}}
{ "error": "This post was removed" }
{{else}}
{{proxy}}
{{/is}}
EOF
}
For scenarios you flip on and off at runtime instead of per request, gate the branch on a flag with {{#hasFlag 'scenario:empty-posts'}} and toggle it from the flags panel or the SDK. The outage example on the Flags page is exactly this shape.