JsonPath Guide for Mockarty
Table of Contents
- What is JsonPath
- Basic Syntax
- Usage Examples
- Data Extraction
- Variables in Responses
- Store Access
- Faker Integration
- 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,0is 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)]
Recursive Search
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
-
Use meaningful names in Store:
"extract": { "cStore": { "userId": "$.req.id", "userEmail": "$.req.email", "sessionStartTime": "$.fake.RFC3339" } } -
Check for data existence:
$.req.user.id || "default-id" $.gS.counter || 0 -
Use filters for complex logic:
$.orders[?(@.status == 'completed' && @.amount > 100)] -
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
payloadfields (JSON), Go Template works intemplateFile.
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