Mock Rules

Template Engine: Dynamic Responses with Expressions and Logic

Use arithmetic, conditionals, dates, JWT and advanced Faker directly in your Mock Rule bodies — no code required.

Why templates instead of static responses?

A Mock Rule with a static body always returns the same JSON. This works for simple cases, but it can't simulate real backend logic: calculating totals, applying different discounts by plan, returning data from the request itself, or evaluating business rules.

httpdrop's template engine is based on Handlebars.js and solves this without requiring code. You write expressions directly in the Mock Rule's Response Body field — the server evaluates them at runtime and returns the result.

🔒
Secure by default: The engine runs in a sandbox — no access to process.env, no prototype pollution (allowProtoPropertiesByDefault: false). Automatic 100ms timeout and output capped at 64KB per response.

Syntax in three lines

Simple call — a helper with arguments
{{helper arg1 arg2}}
Composition — nested helper as argument
{{helper (subHelper arg)}}
Conditional with else
{{#if (operator A B)}}true value{{else}}false value{{/if}}

Arithmetic

Calculate totals, taxes, discounts and conversions in real time. Operators accept literals or subexpressions as arguments.

OperatorExampleResult
add{{add 10 5}}15
subtract{{subtract 10 3}}7
multiply{{multiply 4 2.5}}10
divide{{divide 10 4}}2.5
modulo{{modulo 10 3}}1
floor / ceil / round{{floor 4.9}}4
toFixed{{toFixed 9.999 2}}"10.00"
Mock Rule — POST /checkout — real-time calculation
{
  "qty":      "{{body 'qty'}}",
  "price":    "{{body 'price'}}",
  "subtotal": "{{toFixed (multiply (body 'qty') (body 'price')) 2}}",
  "tax":      "{{toFixed (multiply (multiply (body 'qty') (body 'price')) 0.15) 2}}",
  "total":    "{{toFixed (multiply (multiply (body 'qty') (body 'price')) 1.15) 2}}"
}

String Manipulation

Transform, normalize and encode strings with chainable operators. Useful for generating slugs, deriving emails from names and URL-safe tokens.

OperatorExampleResult
uppercase / lowercase{{uppercase 'hello'}}HELLO
concat{{concat 'foo' 'bar'}}foobar
replace{{replace 'hi world' 'world' 'you'}}hi you
trim{{trim ' hello '}}hello
padStart{{padStart '7' 3 '0'}}007
slugify{{slugify 'João Silva'}}joao-silva
urlEncode{{urlEncode 'a b'}}a%20b
len / substr{{substr 'hello' 0 3}}hel
Mock Rule — POST /profile — slug and email generation
{
  "original": "{{body 'name'}}",
  "slug":     "{{slugify (body 'name')}}",
  "upper":    "{{uppercase (body 'name')}}",
  "email":    "{{concat (lowercase (slugify (body 'name'))) '@example.com'}}",
  "initials": "{{uppercase (substr (body 'name') 0 2)}}"
}

Dates and Expiration

The {{now}} helper accepts a format and a relative offset from the request time. Ideal for simulating JWT tokens with iat/exp, creation logs and due dates.

SyntaxOutput
{{now 'iso'}}2026-05-23T14:30:00.000Z
{{now 'sql'}}2026-05-23 14:30:00
{{now 'unix'}}1748008200000
{{now 'br'}}23/05/2026 14:30
{{now '{days:30}' 'iso'}}30 days in the future
{{now '{days:-7}' 'sql'}}7 days ago (SQL format)
{{now '{months:3}' 'iso'}}3 months from now
Mock Rule — POST /auth/token — token with dynamic expiration
{
  "tokenId":    "{{uuid}}",
  "issuedAt":   "{{now 'iso'}}",
  "expiresAt":  "{{now '{days:30}' 'iso'}}",
  "expiresIn":  2592000,
  "sqlCreated": "{{now 'sql'}}",
  "unix":       "{{now 'unix'}}"
}

Random Selection

{{oneOf}} returns a different value on each request — perfect for simulating systems with variable states like order status, stock availability or risk analysis results.

Mock Rule — GET /order/{id} — random status per call
{
  "orderId":       "{{param 'id'}}",
  "status":        "{{oneOf 'pending' 'processing' 'shipped' 'delivered' 'cancelled'}}",
  "carrier":       "{{oneOf 'Correios' 'Fedex' 'DHL' 'Jadlog'}}",
  "estimatedDays": {{oneOf '1' '2' '3' '5' '7'}}
}

Conditionals Based on Request Data

Use {{#if (operator A B)}} to build responses that depend on any request field. Available comparison operators: eq, gt, lt, gte, lte, isNumber, isInteger, isDate.

Mock Rule — POST /credit-check — tier based on score
{
  "score":       "{{body 'score'}}",
  "approved":    "{{#if (gte (body 'score') 600)}}true{{else}}false{{/if}}",
  "tier":        "{{#if (gte (body 'score') 800)}}platinum{{else}}{{#if (gte (body 'score') 700)}}gold{{else}}standard{{/if}}{{/if}}",
  "creditLimit": "{{#if (gte (body 'score') 800)}}50000{{else}}{{#if (gte (body 'score') 700)}}20000{{else}}5000{{/if}}{{/if}}"
}
Mock Rule — GET /pricing — dynamic price by plan (?tier=pro)
{
  "plan":         "{{query 'tier'}}",
  "monthlyPrice": "{{#if (eq (query 'tier') 'pro')}}99{{else}}{{#if (eq (query 'tier') 'business')}}299{{else}}0{{/if}}{{/if}}",
  "users":        "{{#if (eq (query 'tier') 'business')}}unlimited{{else}}5{{/if}}"
}

Request Data

Any data from the incoming request can be used as a variable in the response — JSON body, query params, headers, path params, HTTP method and the full path.

HelperExampleUse
body 'field'{{body 'user.name'}}JSON body field (dot notation supported)
query 'param'{{query 'page'}}Query string (?page=2)
header 'name'{{header 'x-tenant'}}HTTP header (lowercase)
param 'id'{{param 'id'}}Path param (/users/{id})
method{{method}}HTTP method of the request
reqPath{{reqPath}}Full request path
Mock Rule — POST /echo — mirrors everything from the request
{
  "method":      "{{method}}",
  "path":        "{{reqPath}}",
  "queryPage":   "{{query 'page'}}",
  "contentType": "{{header 'content-type'}}",
  "bodyName":    "{{body 'name'}}",
  "requestId":   "{{uuid}}"
}

JWT — Decoding the Request Token

Use {{jwtPayload}} and {{jwtHeader}} to extract fields from the Bearer token sent in the request. Ideal for simulating authenticated endpoints that return data about the user themselves.

Mock Rule — GET /me — user profile via JWT
{
  "userId":    "{{jwtPayload (header 'authorization') 'sub'}}",
  "email":     "{{jwtPayload (header 'authorization') 'email'}}",
  "role":      "{{jwtPayload (header 'authorization') 'role'}}",
  "algorithm": "{{jwtHeader (header 'authorization') 'alg'}}"
}
🔑
Test token: Use Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1c2VyXzEyMyIsImVtYWlsIjoidGVzdGVAZXhhbXBsZS5jb20iLCJyb2xlIjoiYWRtaW4ifQ.sig as the Authorization header — the engine decodes the payload and returns {"userId":"user_123","email":"teste@example.com","role":"admin","algorithm":"HS256"}. The signature is not validated.

Store — Persistent Counters

The K-V Store persists values per key, per endpoint, while the server is running. Ideal for simulating rate limiting, state sequences and call counters.

Mock Rule — GET /api/data — rate limit to 3 calls
{
  "callCount": {{storeIncr 'hits'}},
  "allowed":   "{{#if (lte (storeGet 'hits') 3)}}true{{else}}false{{/if}}",
  "message":   "{{#if (lte (storeGet 'hits') 3)}}OK ({{storeGet 'hits'}}/3){{else}}Rate limit exceeded{{/if}}"
}

Make 5 calls to the endpoint — the first 3 return allowed: "true"; subsequent ones return false. Use {{storeReset 'hits'}} in another rule to reset the counter.

Advanced Faker

The new {{faker 'category.generator' 'options'}} syntax unlocks generators with parameters — numeric ranges, date formats, float precision. Fully compatible with legacy {{faker.field}} syntax.

New syntaxLegacyOutput
{{faker 'name'}}{{faker.name}}Ana Ribeiro
{{faker 'cpf'}}{{faker.cpf}}123.456.789-09
{{faker 'number.int' '{min:300,max:850}'}}647 (int in range)
{{faker 'number.float' '{precision:0.01}'}}3.14
{{faker 'date.past' 'iso'}}2023-07-12T...
{{faker 'date.future' 'iso'}}2027-02-18T...
Mock Rule — GET /fake-user — complete registration
{
  "id":         "{{faker 'uuid'}}",
  "name":       "{{faker 'name'}}",
  "email":      "{{faker 'email'}}",
  "cpf":        "{{faker 'cpf'}}",
  "phone":      "{{faker 'phone'}}",
  "score":      {{faker 'number.int' '{min:300,max:850}'}},
  "birthDate":  "{{faker 'date.past' 'iso'}}",
  "nextReview": "{{faker 'date.future' 'iso'}}",
  "address":    "{{faker 'address'}}",
  "zip":        "{{faker 'cep'}}"
}

Backward Compatibility

All legacy syntax is automatically converted to the new syntax before rendering — your existing Mock Rules keep working without any changes.

Legacy syntaxNew equivalent
{{faker.cpf}}{{faker 'cpf'}}
{{req.body.field}}{{body 'field'}}
{{req.query.x}}{{query 'x'}}
{{req.headers.x}}{{header 'x'}}
{{req.params.id}}{{param 'id'}}
{{env.KEY}}{{env 'KEY'}}
{{base64.x,y}}{{base64Combine x y}}
{{uuid}} / {{timestamp}}kept as-is (no conversion)

Real-world use cases

🏦
Fintech / KYC — Simulate credit analysis with dynamic score, calculated tier (platinum/gold/standard) and conditional credit limit. The front-end receives different responses based on the score sent in the body.
🛍️
E-commerce — Calculate subtotal, tax and total in real time in the checkout mock. Use {{oneOf}} to simulate variable order status and {{faker 'date.future'}} for realistic delivery dates.
🔐
Auth / SSO — Decode the Bearer token from the request with {{jwtPayload}} and return the user's own data at the /me endpoint — no real database needed.
📊
Dashboards & Analytics — Use {{storeIncr}} to accumulate counters across calls and simulate real pagination, view counting and per-endpoint rate limiting.
Production tips: Output capped at 64KB. Render timeout: 100ms. {{env 'KEY'}} only accesses Workspace variables — never process.env. {{storeIncr}} resets when the server restarts.
Ready to implement? Check the full technical documentation with API reference, code examples and detailed parameters.
View docs →