Mock Rules

Conditional Mocks: Different Responses by Body Value

Simulate an endpoint that responds differently depending on the data it receives — like a real tracking, lookup or validation system would.

The problem: one endpoint, several possible outcomes

A plain Mock Rule always returns the same body. But many real integrations don't work that way — a container tracking endpoint, for instance, needs to answer "cleared" for one number and "in transit" for another, with the same endpoint and same method. If your mock only echoes back the input, it never exercises the branching logic your frontend (or business team) actually needs to validate.

Real scenario: a customs clearance system queries containers via POST /lookup, sending an array at the root of the body (common pattern in Kong/enterprise-gateway integrations):

// Incoming request
[
  { "number": "MOLU0987651" }
]

Array-root body: accessing by index

When the body is an array instead of an object, use the index as the first path segment — 0 for the first (and usually only) item:

{{body '0.number'}}
// equivalent to the legacy syntax: {{req.body.0.number}}

Beyond echo: matching by exact value

httpdrop's template engine is Handlebars-based and already registers comparison helpers (eq, gt, lt, gte, lte) usable inside {{#if}} — combined with body, you can match on any field of the incoming payload, at any depth:

// Mock Rule: POST /lookup → 200
[
  {
    "timestamp": "{{timestamp}}",
    "result": [
      {
        "number": "{{body '0.number'}}",
        "status": "{{#if (eq (body '0.number') 'MOLU0987651')}}CLEARED{{else if (eq (body '0.number') 'TCLU1234567')}}IN_TRANSIT{{else}}{{faker.status}}{{/if}}",
        "location": "{{faker.city}}",
        "updatedAt": "{{timestamp}}"
      }
    ]
  }
]
💡
Always have a fallback: the final {{else}} in the chain should never be an error — use {{faker.xxx}} to return a plausible value even for inputs you didn't explicitly map. That way an unmapped value doesn't block the rest of the team's testing.

When the value map grows too large

Chaining {{#if}}...{{else if}}...{{/if}} works well up to 4-5 mapped values. Beyond that, consider:

  • If the value also appears in the URL (e.g. /lookup/:number), prefer a Path Pattern rule instead of matching on the body.
  • If you need many data variations, not branching logic (names, emails, plausible numbers), use Faker instead of mapping each case by hand.
  • If the pattern repeats across many real captured containers, the generalize_from_traffic MCP tool generalizes it automatically from the endpoint's request history.
🚀
Next step: see the full comparison and conditional operator reference in the template engine guide, or the technical docs for every available helper.
Ready to implement? Check the full technical documentation with API reference, code examples and detailed parameters.
View docs →