Docs JsonPath Guide

JsonPath Guide for Mockarty

Table of Contents

  1. What is JsonPath
  2. Basic Syntax
  3. Usage Examples
  4. Data Extraction
  5. Variables in Responses
  6. Store Access
  7. Faker Integration
  8. Advanced Examples

What is JsonPath

JsonPath is a query language for JSON documents, similar to XPath for XML. In Mockarty, JsonPath is used for:

  • Extracting data from incoming requests
  • Accessing Store data (Global, Chain, Mock)
  • Generating dynamic responses with variables using Faker
  • Evaluating conditions in conditions

Library

Mockarty uses the github.com/PaesslerAG/jsonpath library with extended syntax support.


Basic Syntax

Basic Expressions

Expression Description Example
$ Document root $.user
. Current node $.user.name
[] Index/key access $.items[0], $.user['name']
* All elements $.users[*].name
.. Recursive search $..email
?() Filter $.items[?(@.price > 100)]

Mockarty Special Prefixes

Prefix Description Example
$.req Request body $.req.userId
$.reqHeader Request headers $.reqHeader.Authorization[0]
$.queryParams HTTP query parameters $.queryParams.limit
$.pathParam Path parameters from URL $.pathParam.id
$.mS Mock Store $.mS.savedValue
$.cS Chain Store $.cS.sessionId
$.gS Global Store $.gS.counter
$.fake Faker data $.fake.FirstName
$.response Response data (for webhook) $.response.orderId
$.namespace Current namespace $.namespace

Math Functions

Function Description Example
$.increment(expr || default) Increment value by 1 $.increment($.gS.counter || 0)
$.sum(expr1, expr2) Sum of two values $.sum($.req.price, $.req.tax)
$.multiply(expr1, expr2) Multiply two values $.multiply($.req.quantity, $.req.price)
$.subtract(expr1, expr2) Subtraction (expr1 - expr2) $.subtract($.req.total, $.req.discount)

Arguments can be:

  • Numeric literals: $.sum(10, 20)
  • JsonPath expressions: $.sum($.req.a, $.req.b)
  • Store references: $.sum($.gS.total, $.req.amount)
  • Expressions with default: $.increment($.gS.counter || 0) — if the value is missing, 0 is used

Usage Examples

Simple Extraction

JSON document:

{
  "user": {
    "id": 123,
    "name": "John Doe",
    "email": "john@example.com"
  }
}

JsonPath expressions:

$.user.id        // → 123
$.user.name      // → "John Doe"
$.user.email     // → "john@example.com"
$['user']['id']  // → 123 (alternative syntax)

Working with Arrays

JSON document:

{
  "users": [
    {"id": 1, "name": "John", "active": true},
    {"id": 2, "name": "Jane", "active": false},
    {"id": 3, "name": "Bob", "active": true}
  ]
}

JsonPath expressions:

$.users[0]             // → {"id": 1, "name": "John", "active": true}
$.users[0].name        // → "John"
$.users[-1]            // → {"id": 3, "name": "Bob", "active": true} (last element)
$.users[*].name        // → ["John", "Jane", "Bob"]
$.users[*].id          // → [1, 2, 3]

Filtering

// Active users
$.users[?(@.active == true)]
// → [{"id": 1, "name": "John", "active": true}, {"id": 3, "name": "Bob", "active": true}]

// Names of active users
$.users[?(@.active == true)].name
// → ["John", "Bob"]

// Users with ID greater than 1
$.users[?(@.id > 1)]

// Users with name containing "J"
$.users[?(@.name =~ /.*J.*/i)]

JSON document:

{
  "company": {
    "departments": [
      {
        "name": "IT",
        "employees": [
          {"name": "John", "email": "john@company.com"},
          {"name": "Jane", "email": "jane@company.com"}
        ]
      },
      {
        "name": "HR",
        "head": {"name": "Bob", "email": "bob@company.com"}
      }
    ]
  }
}

JsonPath expressions:

$..email    // → ["john@company.com", "jane@company.com", "bob@company.com"]
$..name     // → ["IT", "John", "Jane", "HR", "Bob"]

Data Extraction

Extracting from Request

HTTP request:

POST /api/users
{
  "user": {
    "name": "John Doe",
    "email": "john@example.com",
    "preferences": {
      "theme": "dark",
      "notifications": true
    }
  }
}

Extraction in Mock:

{
  "extract": {
    "mStore": {
      "userName": "$.req.user.name",
      "userEmail": "$.req.user.email",
      "userTheme": "$.req.user.preferences.theme"
    },
    "gStore": {
      "lastUserName": "$.req.user.name"
    }
  }
}

Extracting Headers

HTTP request:

POST /api/data
Authorization: Bearer abc123token
Content-Type: application/json
X-User-ID: user-456

Extraction:

{
  "extract": {
    "mStore": {
      "authToken": "$.reqHeader.Authorization[0]",
      "userId": "$.reqHeader['X-User-ID'][0]",
      "contentType": "$.reqHeader['Content-Type'][0]"
    }
  }
}

Important: Headers are arrays (a single header can have multiple values). Use [0] to get the first value.

Extracting Path Parameters

For routes with parameters (:id, :userId) use $.pathParam:

Route: /api/users/:userId/orders/:orderId

Request: GET /api/users/abc-123/orders/ord-456

{
  "response": {
    "payload": {
      "userId": "$.pathParam.userId",
      "orderId": "$.pathParam.orderId",
      "message": "Order $.pathParam.orderId for user $.pathParam.userId"
    }
  }
}

Extracting Query Parameters

For query strings (?limit=10&offset=20) use $.queryParams:

Request: GET /api/users?limit=10&offset=20&sort=name

{
  "response": {
    "payload": {
      "limit": "$.queryParams.limit",
      "offset": "$.queryParams.offset",
      "sort": "$.queryParams.sort"
    }
  }
}

You can use query parameters in conditions:

{
  "conditions": [
    {
      "queryParam": "status",
      "assertAction": "equals",
      "value": "active"
    }
  ]
}

Complex Conditions

{
  "conditions": [
    {
      "path": "$.order.items[*].price",
      "assertAction": "contains",
      "value": 100
    },
    {
      "path": "$.order.items[?(@.category == 'electronics')].price",
      "assertAction": "matches",
      "value": "^[1-9]\\d{2,}$"
    }
  ]
}

Variables in Responses

Using Extracted Data

{
  "response": {
    "statusCode": 201,
    "payload": {
      "id": "$.fake.UUIDDigit",
      "name": "$.req.user.name",
      "email": "$.req.user.email",
      "welcomeMessage": "Hello $.req.user.name!",
      "timestamp": "$.fake.RFC3339",
      "preferences": "$.req.user.preferences"
    }
  }
}

Combining Values

{
  "response": {
    "payload": {
      "fullName": "$.req.firstName $.req.lastName",
      "displayName": "Mr. $.req.lastName",
      "loginUrl": "https://example.com/login?user=$.req.userId"
    }
  }
}

Store Access

For a complete guide on Store systems, see the Store Systems documentation.

Global Store

Saving to Global Store:

{
  "extract": {
    "gStore": {
      "totalUsers": "$.increment($.gS.totalUsers || 0)",
      "lastActiveUser": "$.req.userId",
      "systemStats": {
        "lastRequest": "$.fake.RFC3339",
        "version": "1.0.0"
      }
    }
  }
}

Using Global Store:

{
  "response": {
    "payload": {
      "userId": "$.req.id",
      "totalUsersInSystem": "$.gS.totalUsers",
      "lastActiveUser": "$.gS.lastActiveUser",
      "systemVersion": "$.gS.systemStats.version"
    }
  }
}

Chain Store

First mock in the chain:

{
  "chainId": "user-registration",
  "extract": {
    "cStore": {
      "userId": "$.fake.UUIDDigit",
      "userEmail": "$.req.email",
      "registrationTime": "$.fake.RFC3339"
    }
  },
  "response": {
    "payload": {
      "userId": "$.cS.userId",
      "status": "registered"
    }
  }
}

Second mock in the chain:

{
  "chainId": "user-registration",
  "response": {
    "payload": {
      "userId": "$.cS.userId",
      "email": "$.cS.userEmail",
      "registeredAt": "$.cS.registrationTime",
      "status": "verified"
    }
  }
}

Faker Integration

For a complete list of all available Faker functions, see the Faker Reference.

Basic Faker Functions

{
  "response": {
    "payload": {
      "id": "$.fake.UUID",
      "name": "$.fake.FirstName",
      "lastName": "$.fake.LastName",
      "email": "$.fake.Email",
      "phone": "$.fake.Phone",
      "address": "$.fake.Address",
      "city": "$.fake.City",
      "country": "$.fake.Country",
      "company": "$.fake.Company",
      "jobTitle": "$.fake.JobTitle",
      "website": "$.fake.URL",
      "avatar": "$.fake.ImageURL",
      "birthDate": "$.fake.Date",
      "timestamp": "$.fake.RFC3339",
      "unixTime": "$.fake.UnixTime"
    }
  }
}

Numeric Faker Functions

{
  "response": {
    "payload": {
      "randomInt": "$.fake.Int",
      "positiveInt": "$.fake.PositiveInt",
      "negativeInt": "$.fake.NegativeInt",
      "float": "$.fake.Float64",
      "price": "$.fake.Price",
      "latitude": "$.fake.Latitude",
      "longitude": "$.fake.Longitude",
      "boolean": "$.fake.Bool"
    }
  }
}

Localized Data

{
  "response": {
    "payload": {
      "russianName": "$.fake.RussianFirstNameMale",
      "russianSurname": "$.fake.RussianLastNameMale",
      "chineseName": "$.fake.ChineseFirstName",
      "germanName": "$.fake.GermanFirstName",
      "sentence": "$.fake.Sentence",
      "paragraph": "$.fake.Paragraph",
      "word": "$.fake.Word"
    }
  }
}

Math Operations

Detailed Examples

Counter with Increment

{
  "extract": {
    "gStore": {
      "visitCount": "$.increment($.gS.visitCount || 0)"
    }
  },
  "response": {
    "payload": {
      "visits": "$.gS.visitCount"
    }
  }
}

On each call, visitCount is incremented by 1. The || 0 construct sets the initial value if the key does not exist.

Summation and Multiplication

{
  "response": {
    "payload": {
      "subtotal": "$.req.price",
      "tax": "$.multiply($.req.price, 0.2)",
      "total": "$.sum($.req.price, $.multiply($.req.price, 0.2))",
      "discount": "$.subtract($.req.price, 10)"
    }
  }
}

Important: Math functions work with numeric values. Strings are automatically converted to numbers. If conversion is not possible, the value 0 is used.

String Interpolation

JsonPath expressions can be embedded directly into text strings:

{
  "response": {
    "payload": {
      "greeting": "Hello $.req.name, welcome!",
      "link": "https://example.com/users/$.pathParam.id/profile",
      "message": "Order #$.fake.UUIDDigit confirmed for $.req.email"
    }
  }
}

All $.xxx expressions within strings are automatically replaced with their corresponding values.


Advanced Examples

Dynamic Counter

{
  "id": "counter-example",
  "http": {
    "route": "/api/counter"
  },
  "response": {
    "payload": {
      "currentCount": "$.gS.counter",
      "incrementedCount": "$.increment($.gS.counter || 0)",
      "timestamp": "$.fake.RFC3339"
    }
  },
  "extract": {
    "gStore": {
      "counter": "$.increment($.gS.counter || 0)",
      "lastIncrement": "$.fake.RFC3339"
    }
  }
}

User Management Chain

Registration (Step 1):

{
  "id": "user-register",
  "chainId": "user-lifecycle",
  "http": {
    "route": "/api/auth/register",
    "httpMethod": "POST"
  },
  "response": {
    "payload": {
      "userId": "$.fake.UUIDDigit",
      "email": "$.req.email",
      "status": "pending_verification",
      "verificationCode": "$.fake.Zip"
    }
  },
  "extract": {
    "cStore": {
      "userId": "$.fake.UUIDDigit",
      "userEmail": "$.req.email",
      "verificationCode": "$.fake.Zip",
      "registeredAt": "$.fake.RFC3339"
    },
    "gStore": {
      "totalRegistrations": "$.increment($.gS.totalRegistrations || 0)"
    }
  }
}

Verification (Step 2):

{
  "id": "user-verify",
  "chainId": "user-lifecycle",
  "http": {
    "route": "/api/auth/verify",
    "httpMethod": "POST",
    "conditions": [
      {
        "assertAction": "equals",
        "value": {
          "code": "$.cS.verificationCode"
        }
      }
    ]
  },
  "response": {
    "payload": {
      "userId": "$.cS.userId",
      "email": "$.cS.userEmail",
      "status": "verified",
      "verifiedAt": "$.fake.RFC3339",
      "accessToken": "$.fake.JWT"
    }
  },
  "extract": {
    "cStore": {
      "isVerified": true,
      "verifiedAt": "$.fake.RFC3339",
      "accessToken": "$.fake.JWT"
    }
  }
}

Profile (Step 3):

{
  "id": "user-profile",
  "chainId": "user-lifecycle",
  "http": {
    "route": "/api/users/profile",
    "httpMethod": "GET",
    "header": [
      {
        "assertAction": "contains",
        "value": {
          "Authorization": "Bearer $.cS.accessToken"
        }
      }
    ]
  },
  "response": {
    "payload": {
      "userId": "$.cS.userId",
      "email": "$.cS.userEmail",
      "verified": "$.cS.isVerified",
      "registeredAt": "$.cS.registeredAt",
      "verifiedAt": "$.cS.verifiedAt",
      "profile": {
        "name": "$.fake.FirstName",
        "lastName": "$.fake.LastName",
        "avatar": "$.fake.ImageURL",
        "bio": "$.fake.Sentence",
        "preferences": {
          "theme": "dark",
          "language": "en",
          "notifications": true
        }
      },
      "stats": {
        "loginCount": "$.fake.IntBetween(1, 50)",
        "lastLogin": "$.fake.RFC3339",
        "totalUsers": "$.gS.totalRegistrations"
      }
    }
  }
}

E-commerce Order Processing

{
  "id": "process-order",
  "http": {
    "route": "/api/orders",
    "httpMethod": "POST",
    "conditions": [
      {
        "path": "$.items[*].quantity",
        "assertAction": "matches",
        "value": "^[1-9]\\d*$"
      },
      {
        "path": "$.customer.email",
        "assertAction": "matches",
        "value": "^[\\w\\.-]+@[\\w\\.-]+\\.[a-zA-Z]{2,}$"
      }
    ]
  },
  "response": {
    "payload": {
      "orderId": "$.fake.UUIDDigit",
      "customer": "$.req.customer",
      "items": "$.req.items",
      "summary": {
        "estimatedTotal": "$.fake.Float64(50.0, 500.0)",
        "currency": "USD",
        "orderedItems": "$.req.items"
      },
      "fulfillment": {
        "estimatedDelivery": "$.fake.FutureDate",
        "trackingNumber": "$.fake.Zip",
        "carrier": "$.fake.Company"
      },
      "timestamps": {
        "orderedAt": "$.fake.RFC3339",
        "estimatedShipping": "$.fake.FutureDate",
        "estimatedDelivery": "$.fake.FutureDate"
      }
    }
  },
  "extract": {
    "mStore": {
      "orderId": "$.fake.UUIDDigit",
      "customerEmail": "$.req.customer.email"
    },
    "gStore": {
      "totalOrders": "$.increment($.gS.totalOrders || 0)",
      "lastOrderTime": "$.fake.RFC3339"
    }
  }
}

Analytics Mock

{
  "id": "analytics-report",
  "http": {
    "route": "/api/analytics/report",
    "queryParams": [
      {
        "path": "$.period",
        "assertAction": "matches",
        "value": "^(daily|weekly|monthly)$"
      }
    ]
  },
  "response": {
    "payload": {
      "report": {
        "period": "$.req.query.period",
        "generatedAt": "$.fake.RFC3339",
        "metrics": {
          "totalUsers": "$.gS.totalRegistrations",
          "totalOrders": "$.gS.totalOrders",
          "activeUsers": "$.fake.IntBetween(100, 1000)",
          "revenue": "$.fake.Float64(10000.0, 100000.0)",
          "conversionRate": "$.fake.Float64(0.1, 0.3)"
        },
        "trends": {
          "userGrowth": "$.fake.Float64(-0.1, 0.2)",
          "orderGrowth": "$.fake.Float64(-0.05, 0.15)",
          "revenueGrowth": "$.fake.Float64(-0.2, 0.3)"
        },
        "topProducts": [
          {
            "id": "$.fake.UUIDDigit",
            "name": "$.fake.ProductName",
            "sales": "$.fake.IntBetween(50, 500)",
            "revenue": "$.fake.Float64(1000.0, 10000.0)"
          }
        ]
      }
    }
  }
}

Utilities for Working with JsonPath

Testing JsonPath

Testing endpoint:

curl -X POST http://localhost:5770/mock/util/extractJpath \
  -H "Content-Type: application/json" \
  -d '{
    "jpath": "$.users[*].email",
    "from": {
      "users": [
        {"name": "John", "email": "john@example.com"},
        {"name": "Jane", "email": "jane@example.com"}
      ]
    }
  }'

Response:

{
  "result": ["john@example.com", "jane@example.com"],
  "jpath": "$.users[*].email"
}

Debugging Expressions

Example debug mock:

{
  "id": "debug-jsonpath",
  "http": {
    "route": "/debug/jsonpath"
  },
  "response": {
    "payload": {
      "request": "$.req",
      "headers": "$.reqHeader",
      "mockStore": "$.mS",
      "chainStore": "$.cS",
      "globalStore": "$.gS",
      "fakeData": {
        "uuid": "$.fake.UUID",
        "name": "$.fake.FirstName",
        "email": "$.fake.Email"
      }
    }
  }
}

Best Practices

  1. Use meaningful names in Store:

    "extract": {
      "cStore": {
        "userId": "$.req.id",
        "userEmail": "$.req.email",
        "sessionStartTime": "$.fake.RFC3339"
      }
    }
    
  2. Check for data existence:

    $.req.user.id || "default-id"
    $.gS.counter || 0
    
  3. Use filters for complex logic:

    $.orders[?(@.status == 'completed' && @.amount > 100)]
    
  4. Combine static and dynamic data:

    {
      "message": "Hello $.req.name! Your order #$.fake.UUIDDigit is confirmed",
      "timestamp": "$.fake.RFC3339"
    }
    

XML Support

JsonPath expressions also work inside XML responses (SOAP mocks):

{
  "response": {
    "payload": "<GetUserResponse><UserId>$.pathParam.id</UserId><Name>$.fake.FirstName</Name><Email>$.fake.Email</Email></GetUserResponse>"
  }
}

Mockarty automatically escapes XML special characters (<, >, &, ", ') when substituting values into XML strings. It also normalizes whitespace in namespaces and attributes.


Go Template Mode

In addition to JsonPath, Mockarty supports Go Template syntax for file templates. Load a template from a file using the templateFile field:

{
  "response": {
    "templateFile": "my-template.json"
  }
}

Available functions inside Go Template:

Function Description Example
req Request data {{req .Request "user.name"}}
reqHeader Header data {{reqHeader .Headers "Authorization"}}
fake Faker data {{fake "FirstName"}}
mS Mock Store {{mS .MStore "key"}}
cS Chain Store {{cS .CStore "key"}}
gS Global Store {{gS .GStore "key"}}
asJson Convert to JSON {{asJson .Request}}

Important: Go Template and JsonPath are two different modes. JsonPath works in payload fields (JSON), Go Template works in templateFile.


Use this guide to create powerful dynamic mocks with JsonPath!


See Also

  • Faker Reference – all available Faker functions for generating test data
  • Store Systems – Global, Chain, and Mock stores for stateful mocks
  • API Reference – complete REST API including the JsonPath test endpoint
  • Web UI Guide – visual mock constructor with JsonPath support
  • Quick Start – get started with your first dynamic mock