Predicates

Predicates define rules for matching incoming requests. When all predicates in a stub match, the stub’s response is returned.


Request Fields

Predicates can match on these request fields:

Field Description Example
method HTTP method GET, POST, PUT, DELETE
path Request path /api/users
query Query parameters { "page": "1" }
headers Request headers { "Authorization": "Bearer..." }
body Request body String or JSON object

Predicate Types

equals

Exact match on request fields:

{
  "equals": {
    "method": "GET",
    "path": "/users",
    "query": { "active": "true" }
  }
}

Match headers (case-insensitive by default):

{
  "equals": {
    "headers": { "Content-Type": "application/json" }
  }
}

Match JSON body:

{
  "equals": {
    "body": { "username": "admin", "password": "secret" }
  }
}

deepEquals

Like equals but requires exact object structure (no extra fields):

{
  "deepEquals": {
    "body": { "id": 1, "name": "Test" }
  }
}

Works on all request fields - useful for strict matching:

{
  "deepEquals": {
    "method": "GET",
    "path": "/api/users",
    "body": ""
  }
}

contains

Partial match - checks if value is contained:

{
  "contains": {
    "path": "/api",
    "body": { "action": "create" }
  }
}

Match substring in query parameter values:

{
  "contains": {
    "query": { "lenderIds": "Test" }
  }
}

This matches requests like ?lenderIds=TestUser or ?lenderIds=MyTestValue.

startsWith

Match beginning of string:

{
  "startsWith": {
    "path": "/api/v1"
  }
}

endsWith

Match end of string:

{
  "endsWith": {
    "path": ".json"
  }
}

matches

Regular expression match:

{
  "matches": {
    "path": "/users/\\d+",
    "headers": { "Authorization": "Bearer [A-Za-z0-9]+" }
  }
}

exists

Check field existence:

{
  "exists": {
    "headers": { "X-Api-Key": true },
    "query": { "debug": false }
  }
}
  • true - Field must exist
  • false - Field must not exist

JSONPath Predicates

Match specific values in JSON bodies using JSONPath. The jsonpath selector is combined with a predicate operation:

{
  "jsonpath": { "selector": "$.user.name" },
  "equals": { "body": "admin" }
}

JSONPath Operators

// Equals - match exact value
{ "jsonpath": { "selector": "$.count" }, "equals": { "body": 10 } }

// Contains - partial match
{ "jsonpath": { "selector": "$.tags" }, "contains": { "body": "important" } }

// Matches - regex pattern
{ "jsonpath": { "selector": "$.email" }, "matches": { "body": ".*@example\\.com" } }

// Exists - check field presence
{ "jsonpath": { "selector": "$.optional" }, "exists": { "body": true } }

JSONPath Examples

// Match array element
{ "jsonpath": { "selector": "$.items[0].name" }, "equals": { "body": "First Item" } }

// Match nested value
{ "jsonpath": { "selector": "$.user.address.city" }, "equals": { "body": "NYC" } }

// Match with filter
{ "jsonpath": { "selector": "$.items[?(@.price > 100)]" }, "exists": { "body": true } }

XPath Predicates

Match values in XML bodies using XPath:

{
  "xpath": {
    "selector": "//user/name",
    "equals": "admin"
  }
}

XPath with Namespaces

{
  "xpath": {
    "selector": "//ns:item/ns:price",
    "ns": { "ns": "http://example.com/schema" },
    "equals": "99.99"
  }
}

Logical Operators

and

All predicates must match:

{
  "and": [
    { "equals": { "method": "POST" } },
    { "equals": { "path": "/api/users" } },
    { "contains": { "body": { "role": "admin" } } }
  ]
}

or

At least one predicate must match:

{
  "or": [
    { "equals": { "path": "/api/v1/users" } },
    { "equals": { "path": "/api/v2/users" } }
  ]
}

not

Predicate must not match:

{
  "not": {
    "equals": { "method": "DELETE" }
  }
}

Complex Combinations

{
  "and": [
    { "equals": { "method": "POST" } },
    {
      "or": [
        { "contains": { "body": { "type": "A" } } },
        { "contains": { "body": { "type": "B" } } }
      ]
    },
    {
      "not": {
        "exists": { "headers": { "X-Test-Skip": true } }
      }
    }
  ]
}

Predicate Options

caseSensitive

Enable case-sensitive matching (default: false):

{
  "equals": { "path": "/API/Users" },
  "caseSensitive": true
}

except

Exclude fields from matching:

{
  "equals": { "body": { "id": 1, "name": "Test" } },
  "except": "body.timestamp"
}

Common Patterns

Match Any GET Request

{ "equals": { "method": "GET" } }

Match Path with ID

{ "matches": { "path": "/users/[0-9a-f-]+" } }

Match JSON Content-Type

{
  "and": [
    { "equals": { "method": "POST" } },
    { "contains": { "headers": { "Content-Type": "application/json" } } }
  ]
}

Match Authenticated Requests

{ "exists": { "headers": { "Authorization": true } } }

Match Query Parameters

{
  "equals": {
    "query": { "page": "1", "limit": "10" }
  }
}

Multiple Predicates (Implicit AND)

When you specify multiple predicates in a stub’s predicates array, they are combined with implicit AND - all must match:

{
  "predicates": [
    { "endsWith": { "path": "/lender-details" } },
    { "contains": { "query": { "lenderIds": "ALL" } } },
    { "deepEquals": { "method": "GET" } }
  ],
  "responses": [{ "is": { "statusCode": 200 } }]
}

This matches GET requests to paths ending in /lender-details with query parameter lenderIds containing “ALL”.


Stub Ordering

Stubs are evaluated in order. Place more specific predicates first:

{
  "stubs": [
    {
      "predicates": [{ "equals": { "path": "/users/admin" } }],
      "responses": [{ "is": { "body": "Admin user" } }]
    },
    {
      "predicates": [{ "matches": { "path": "/users/.*" } }],
      "responses": [{ "is": { "body": "Regular user" } }]
    },
    {
      "predicates": [],
      "responses": [{ "is": { "statusCode": 404 } }]
    }
  ]
}