Docs Store Systems

Store Systems in Mockarty

Table of Contents

  1. Store Systems Overview
  2. Mock Store (MStore)
  3. Chain Store (CStore)
  4. Global Store (GStore)
  5. Store Management API
  6. Usage Examples
  7. Best Practices

Tip: Code examples are available for cURL, CLI, and SDK clients (Go, Python, Java). See the SDK Guide for installation and setup. See the CLI User Guide for the command-line tool.

About URLs in examples: All examples use localhost:5770 as the default Mockarty address. If your instance runs on a remote server, replace localhost:5770 with its actual address (e.g. https://mockarty.company.com or http://192.168.1.50:5770). See Tips & Useful Features for details.

Store Systems Overview

Key Concepts for Beginners

Before diving into Store systems, here are a few key terms:

  • Mock – a simulated API endpoint that returns predefined responses instead of calling a real service.
  • Namespace – a logical grouping of mocks (like a folder). Mocks in different namespaces are isolated from each other.
  • Chain – a sequence of related mocks that share state. For example, “create order” -> “pay for order” -> “ship order” form a chain.
  • Extract – the process of pulling data from a request (or generating data) and saving it into a store for later use.
  • JsonPath – a query language (like $.mS.userId) used to reference stored values in mock responses.

When to Use Which Store

Not sure which store to pick? Use this simple decision guide:

  • Mock Store (mS) – Use when you need temporary data within a single mock call. Example: generate a UUID and use it in multiple places in the same response. Data disappears after the request is processed.
  • Chain Store (cS) – Use when you need to share data between related mocks that form a workflow. Example: a user registration flow where the registration mock saves a userId, and the profile mock reads it. Data persists across calls within the same chain.
  • Global Store (gS) – Use when you need shared state across all mocks in a namespace. Example: request counters, feature flags, or system configuration. Data persists indefinitely until explicitly cleared.

Store Concept

Store is a data storage system in Mockarty that allows you to:

  • Save data between mock invocations
  • Share data between related mocks
  • Accumulate state for complex scenarios
  • Create dynamic responses based on accumulated data using JsonPath and Faker

Store Architecture

graph TB
    subgraph "Store Hierarchy"
        MSTORE["Mock Store (mS)"]
        CSTORE["Chain Store (cS)"]
        GSTORE["Global Store (gS)"]
    end

    subgraph "Scope"
        MOCK_SCOPE["Single Mock"]
        CHAIN_SCOPE["Chain of Mocks"]
        GLOBAL_SCOPE["All Mocks in Namespace"]
    end

    subgraph "Persistence"
        SESSION["Ephemeral (request only)"]
        PERMANENT["Persistent (database)"]
        NAMESPACE_ISOLATED["Persistent + Namespace Isolated"]
    end

    MSTORE --> MOCK_SCOPE
    CSTORE --> CHAIN_SCOPE
    GSTORE --> GLOBAL_SCOPE

    MSTORE --> SESSION
    CSTORE --> PERMANENT
    GSTORE --> NAMESPACE_ISOLATED

    classDef store fill:#4a90d9,stroke:#2c5f8a,color:#fff
    classDef scope fill:#8e6fbf,stroke:#5e4590,color:#fff
    classDef persistence fill:#5aad6e,stroke:#3a7d4e,color:#fff

    class MSTORE,CSTORE,GSTORE store
    class MOCK_SCOPE,CHAIN_SCOPE,GLOBAL_SCOPE scope
    class SESSION,PERMANENT,NAMESPACE_ISOLATED persistence

Store Type Comparison

Store Type Scope Lifetime Namespace JsonPath Access
MStore Local mock During mock processing N/A $.mS.key
CStore All mocks in Chain Permanent Yes $.cS.key
GStore All mocks in Namespace Permanent Yes $.gS.key

Store Management UI

The Stores page in the Mockarty web UI provides a visual interface for viewing and managing all three store types. Use the tabs at the top to switch between Global Store, Chain Store, and Mock Store.

Stores page – Global Store tab

Note: Store writes from extract operations are performed asynchronously. Values may not be immediately available in the very next request if they arrive simultaneously.


Mock Store (MStore)

What is Mock Store?

Mock Store (MStore) is a local data storage for a specific mock, available only during the processing of that mock.

Mock Store tab – ephemeral per-request storage

Features:

  • Isolation – data is accessible only within a specific mock
  • Ephemeral – data exists only during request processing
  • Fast – stored in mock memory
  • Simple – does not require namespace or chainId management

Using MStore

Extracting to MStore

{
  "id": "user-create",
  "http": {
    "route": "/api/users",
    "httpMethod": "POST"
  },
  "response": {
    "payload": {
      "id": "$.mS.generatedId",
      "name": "$.req.name",
      "email": "$.req.email",
      "clientIP": "$.mS.clientIP",
      "userAgent": "$.mS.userAgent"
    }
  },
  "extract": {
    "mStore": {
      "generatedId": "$.fake.UUIDDigit",
      "requestTime": "$.fake.RFC3339",
      "clientIP": "$.reqHeader['X-Forwarded-For'][0]",
      "userAgent": "$.reqHeader['User-Agent'][0]",
      "requestCount": "$.increment($.gS.requestCount || 0)"
    }
  }
}

Accessing MStore in the Response

{
  "response": {
    "payload": {
      "userId": "$.mS.generatedId",
      "processedAt": "$.mS.requestTime",
      "metadata": {
        "clientIP": "$.mS.clientIP",
        "userAgent": "$.mS.userAgent",
        "requestCount": "$.mS.requestCount"
      }
    }
  }
}

Typical MStore Use Cases

  1. Generating related IDs:

    "extract": {
      "mStore": {
        "userId": "$.fake.UUIDDigit",
        "profileId": "$.fake.UUIDDigit",
        "sessionId": "$.fake.UUID"
      }
    }
    
  2. Processing request metadata:

    "extract": {
      "mStore": {
        "timestamp": "$.fake.RFC3339",
        "requestId": "$.fake.UUID",
        "traceId": "$.reqHeader['X-Trace-ID'][0]"
      }
    }
    
  3. Math computations:

    "extract": {
      "mStore": {
        "basePrice": "$.req.price",
        "tax": "$.multiply($.req.price, 0.2)",
        "totalPrice": "$.sum($.req.price, $.mS.tax)"
      }
    }
    

Chain Store (CStore)

What is Chain Store?

Chain Store (CStore) is a shared data storage across all mocks with the same chainId within a single namespace.

Chain Store tab – shared state across chained mocks

Features:

  • Shared – data is accessible to all mocks in the chain
  • Persistent – data is preserved between invocations
  • Namespace isolation – data is isolated by namespace
  • Accumulation – data accumulates as the chain progresses

CStore Lifecycle

sequenceDiagram
    participant M1 as Mock 1
    participant CS as Chain Store
    participant M2 as Mock 2
    participant M3 as Mock 3

    M1->>CS: Extract data (step 1)
    CS-->>M1: Store updated

    M2->>CS: Read data from step 1
    CS-->>M2: Return step 1 data
    M2->>CS: Extract additional data (step 2)
    CS-->>M2: Store updated

    M3->>CS: Read data from steps 1 & 2
    CS-->>M3: Return accumulated data
    M3->>CS: Extract final data (step 3)
    CS-->>M3: Store updated (complete)

Using CStore

Initial Mock in the Chain

{
  "id": "order-start",
  "chainId": "order-processing",
  "namespace": "e-commerce",
  "http": {
    "route": "/api/orders/create",
    "httpMethod": "POST"
  },
  "response": {
    "payload": {
      "orderId": "$.fake.UUIDDigit",
      "status": "created",
      "items": "$.req.items"
    }
  },
  "extract": {
    "cStore": {
      "orderId": "$.fake.UUIDDigit",
      "customerId": "$.req.customerId",
      "items": "$.req.items",
      "totalAmount": "$.req.totalAmount",
      "createdAt": "$.fake.RFC3339",
      "currentStep": "created"
    }
  }
}

Intermediate Mock in the Chain

{
  "id": "order-payment",
  "chainId": "order-processing",
  "namespace": "e-commerce",
  "http": {
    "route": "/api/orders/payment",
    "httpMethod": "POST"
  },
  "response": {
    "payload": {
      "orderId": "$.cS.orderId",
      "customerId": "$.cS.customerId",
      "amount": "$.cS.totalAmount",
      "paymentId": "$.fake.UUIDDigit",
      "status": "paid"
    }
  },
  "extract": {
    "cStore": {
      "paymentId": "$.fake.UUIDDigit",
      "paidAt": "$.fake.RFC3339",
      "paymentMethod": "$.req.paymentMethod",
      "currentStep": "paid"
    }
  }
}

Final Mock in the Chain

{
  "id": "order-fulfill",
  "chainId": "order-processing",
  "namespace": "e-commerce",
  "http": {
    "route": "/api/orders/fulfill",
    "httpMethod": "POST"
  },
  "response": {
    "payload": {
      "orderId": "$.cS.orderId",
      "customerId": "$.cS.customerId",
      "paymentId": "$.cS.paymentId",
      "trackingNumber": "$.fake.ZipCode",
      "estimatedDelivery": "$.fake.Date",
      "orderSummary": {
        "items": "$.cS.items",
        "totalAmount": "$.cS.totalAmount",
        "createdAt": "$.cS.createdAt",
        "paidAt": "$.cS.paidAt",
        "fulfilledAt": "$.fake.RFC3339"
      }
    }
  },
  "extract": {
    "cStore": {
      "trackingNumber": "$.fake.ZipCode",
      "fulfilledAt": "$.fake.RFC3339",
      "currentStep": "fulfilled",
      "isComplete": true
    }
  }
}

Chain Store API

Retrieving Chain Store Data

GET /api/v1/stores/chain/{chainId}?namespace=e-commerce

Adding Data to Chain Store

Each request adds a single key-value pair. To add multiple entries, make separate requests for each key.

POST /api/v1/stores/chain/order-processing
Content-Type: application/json

{
  "key": "manualStep",
  "value": "admin-review",
  "namespace": "e-commerce"
}

Deleting Data from Chain Store

Delete a single key by specifying it in the URL path:

DELETE /api/v1/stores/chain/order-processing/temporaryData?namespace=e-commerce

Global Store (GStore)

What is Global Store?

Global Store (GStore) is a global data storage accessible to all mocks within a single namespace.

Global Store with data – key-value pairs visible in the UI

Features:

  • Global – data is accessible to all mocks in the namespace
  • Persistent – data is preserved across all invocations
  • Namespace isolation – data is isolated by namespace
  • Accumulation – ideal for counters and statistics

Using GStore

Counters and Statistics

{
  "id": "api-request-counter",
  "namespace": "monitoring",
  "http": {
    "route": "/api/*"
  },
  "response": {
    "payload": {
      "requestId": "$.fake.UUID",
      "timestamp": "$.fake.RFC3339",
      "stats": {
        "totalRequests": "$.increment($.gS.totalRequests || 0)",
        "todayRequests": "$.increment($.gS.todayRequests || 0)",
        "uniqueUsers": "$.gS.uniqueUsers"
      }
    }
  },
  "extract": {
    "gStore": {
      "totalRequests": "$.increment($.gS.totalRequests || 0)",
      "todayRequests": "$.increment($.gS.todayRequests || 0)",
      "lastRequestAt": "$.fake.RFC3339",
      "lastUserID": "$.reqHeader['X-User-ID'][0]"
    }
  }
}

System Configuration

{
  "id": "system-config",
  "namespace": "system",
  "http": {
    "route": "/api/config"
  },
  "response": {
    "payload": {
      "config": {
        "version": "$.gS.systemVersion",
        "maintenanceMode": "$.gS.maintenanceMode",
        "features": "$.gS.enabledFeatures",
        "lastUpdated": "$.gS.configLastUpdated"
      }
    }
  },
  "extract": {
    "gStore": {
      "configAccessed": "$.increment($.gS.configAccessed || 0)",
      "lastConfigAccess": "$.fake.RFC3339"
    }
  }
}

Global State

{
  "id": "feature-toggle",
  "namespace": "features",
  "http": {
    "route": "/api/features/status"
  },
  "response": {
    "payload": {
      "feature": "$.req.featureName",
      "enabled": "$.gS.features.newDashboard.enabled",
      "config": "$.gS.features.newDashboard.config",
      "rolloutPercentage": "$.gS.features.newDashboard.rollout"
    }
  },
  "extract": {
    "gStore": {
      "featureAccessCount": "$.increment($.gS.featureAccessCount || 0)",
      "lastFeatureAccess": "$.fake.RFC3339"
    }
  }
}

Global Store API

Retrieving Global Store Data

GET /api/v1/stores/global?namespace=monitoring

Adding Data to Global Store

Each request adds a single key-value pair. To add multiple entries, make separate requests for each key.

POST /api/v1/stores/global
Content-Type: application/json

{
  "key": "systemVersion",
  "value": "1.2.3",
  "namespace": "monitoring"
}

Deleting Data from Global Store

Delete a single key by specifying it in the URL path:

DELETE /api/v1/stores/global/oldConfig?namespace=monitoring

Store Management API

Full API Reference

For the complete API documentation, see the API Reference.

Global Store Endpoints

Method Endpoint Description
GET /api/v1/stores/global Get Global Store
POST /api/v1/stores/global Add a key-value pair to Global Store
DELETE /api/v1/stores/global/{key} Delete a key from Global Store

Query Parameters:

  • namespace (optional) – namespace (default: “sandbox”)

POST Body: {"key": "...", "value": "...", "namespace": "..."}

Chain Store Endpoints

Method Endpoint Description
GET /api/v1/stores/chain/{chainId} Get Chain Store
POST /api/v1/stores/chain/{chainId} Add a key-value pair to Chain Store
DELETE /api/v1/stores/chain/{chainId}/{key} Delete a key from Chain Store

Path Parameters:

  • chainId – chain ID
  • key – key to delete (for DELETE only)

Query Parameters:

  • namespace (optional) – namespace (default: “sandbox”)

POST Body: {"key": "...", "value": "...", "namespace": "..."}

API Call Examples

Adding to Global Store

Each API call adds a single key-value pair. Make multiple calls to set multiple keys.

cURL

# Add a key-value pair to Global Store
curl -X POST http://localhost:5770/api/v1/stores/global \
  -H "Content-Type: application/json" \
  -d '{"key": "appVersion", "value": "1.0.0", "namespace": "testing"}'

# Add another key
curl -X POST http://localhost:5770/api/v1/stores/global \
  -H "Content-Type: application/json" \
  -d '{"key": "environment", "value": "testing", "namespace": "testing"}'

CLI

mockarty-cli store global set --namespace testing --key appVersion --value "1.0.0"
mockarty-cli store global set --namespace testing --key environment --value "testing"

Go

import mockarty "github.com/mockarty/mockarty-go"

client := mockarty.NewClient("http://localhost:5770", "YOUR_TOKEN")

// Namespace is configured on the client (mockarty.WithNamespace("testing"))
err := client.Stores().GlobalSet(ctx, "appVersion", "1.0.0")
err = client.Stores().GlobalSet(ctx, "environment", "testing")

Python

from mockarty import MockartyClient

client = MockartyClient("http://localhost:5770", token="YOUR_TOKEN")

# Namespace is configured on the client (MockartyClient(..., namespace="testing"))
client.stores.global_set(key="appVersion", value="1.0.0")
client.stores.global_set(key="environment", value="testing")

Java

import ru.mockarty.MockartyClient;

MockartyClient client = new MockartyClient("http://localhost:5770", "YOUR_TOKEN");

client.stores().globalSet("testing", "appVersion", "1.0.0");
client.stores().globalSet("testing", "environment", "testing");

Adding to Chain Store

cURL

curl -X POST http://localhost:5770/api/v1/stores/chain/user-journey \
  -H "Content-Type: application/json" \
  -d '{"key": "journeyStarted", "value": "true", "namespace": "testing"}'

curl -X POST http://localhost:5770/api/v1/stores/chain/user-journey \
  -H "Content-Type: application/json" \
  -d '{"key": "startTime", "value": "2024-01-01T10:00:00Z", "namespace": "testing"}'

CLI

mockarty-cli store chain set user-journey --namespace testing --key journeyStarted --value "true"
mockarty-cli store chain set user-journey --namespace testing --key startTime --value "2024-01-01T10:00:00Z"

Go

err := client.Stores().ChainSet(ctx, "user-journey", "journeyStarted", "true")
err = client.Stores().ChainSet(ctx, "user-journey", "startTime", "2024-01-01T10:00:00Z")

Python

client.stores.chain_set(chain_id="user-journey", key="journeyStarted", value="true")
client.stores.chain_set(chain_id="user-journey", key="startTime", value="2024-01-01T10:00:00Z")

Java

client.stores().chainSet("user-journey", "testing", "journeyStarted", "true");
client.stores().chainSet("user-journey", "testing", "startTime", "2024-01-01T10:00:00Z");

Deleting Store Data

Delete one key at a time by specifying it in the URL path.

cURL

# Delete a key from Global Store
curl -X DELETE http://localhost:5770/api/v1/stores/global/tempData?namespace=testing

# Delete a key from Chain Store
curl -X DELETE http://localhost:5770/api/v1/stores/chain/user-journey/debugData?namespace=testing

CLI

# Delete a key from Global Store
mockarty-cli store global delete --namespace testing --key tempData

# Delete a key from Chain Store
mockarty-cli store chain delete user-journey --namespace testing --key debugData

Go

// Delete a key from Global Store
err := client.Stores().GlobalDelete(ctx, "testing", "tempData")

// Delete a key from Chain Store
err = client.Stores().ChainDelete(ctx, "user-journey", "testing", "debugData")

Python

# Delete a key from Global Store
client.stores.global_delete(namespace="testing", key="tempData")

# Delete a key from Chain Store
client.stores.chain_delete(chain_id="user-journey", namespace="testing", key="debugData")

Java

// Delete a key from Global Store
client.stores().globalDelete("testing", "tempData");

// Delete a key from Chain Store
client.stores().chainDelete("user-journey", "testing", "debugData");

Usage Examples

The sections above already show basic patterns for each store type – counters, configuration, and chain workflows. The examples below demonstrate more advanced scenarios that combine multiple store types or show cross-store interaction.

Complex Chain Scenarios

Multi-step Workflow

{
  "id": "workflow-step-1",
  "chainId": "approval-workflow",
  "namespace": "workflows",
  "http": {
    "route": "/api/workflow/submit",
    "httpMethod": "POST"
  },
  "response": {
    "payload": {
      "workflowId": "$.fake.UUIDDigit",
      "status": "submitted",
      "submittedBy": "$.req.userId",
      "nextStep": "manager-review"
    }
  },
  "extract": {
    "cStore": {
      "workflowId": "$.fake.UUIDDigit",
      "submittedBy": "$.req.userId",
      "submittedAt": "$.fake.RFC3339",
      "currentStep": "submitted",
      "steps": ["submitted"],
      "approvalChain": ["manager", "director", "ceo"]
    },
    "gStore": {
      "totalWorkflows": "$.increment($.gS.totalWorkflows || 0)"
    }
  }
}
{
  "id": "workflow-step-2",
  "chainId": "approval-workflow",
  "namespace": "workflows",
  "http": {
    "route": "/api/workflow/approve",
    "httpMethod": "POST"
  },
  "response": {
    "payload": {
      "workflowId": "$.cS.workflowId",
      "approvedBy": "$.req.approverId",
      "currentStep": "manager-approved",
      "nextStep": "director-review",
      "progress": {
        "submittedBy": "$.cS.submittedBy",
        "submittedAt": "$.cS.submittedAt",
        "percentage": 33
      }
    }
  },
  "extract": {
    "cStore": {
      "managerApprovedBy": "$.req.approverId",
      "managerApprovedAt": "$.fake.RFC3339",
      "currentStep": "manager-approved"
    }
  }
}

Experiment Tracking with Stores

Tracking Experiment Assignments

{
  "id": "experiment-tracker",
  "namespace": "experiments",
  "http": {
    "route": "/api/experiment/assign",
    "httpMethod": "POST"
  },
  "response": {
    "payload": {
      "userId": "$.req.userId",
      "experiment": "new-checkout-flow",
      "variant": "$.req.variant",
      "assignedAt": "$.fake.RFC3339",
      "totalAssignments": "$.gS.totalAssignments"
    }
  },
  "extract": {
    "gStore": {
      "totalAssignments": "$.increment($.gS.totalAssignments || 0)",
      "lastAssignedUser": "$.req.userId",
      "lastAssignedVariant": "$.req.variant",
      "lastAssignedAt": "$.fake.RFC3339"
    }
  }
}

Best Practices

Recommendations

  1. Use the right Store type for the task:

    • MStore – for temporary computations within a mock
    • CStore – for passing data between scenario steps
    • GStore – for global counters and configuration
  2. Structure data in Stores:

    "extract": {
      "gStore": {
        "users": {
          "total": "$.increment($.gS.users.total || 0)",
          "active": "$.gS.users.active || 0",
          "lastRegistered": "$.fake.RFC3339"
        },
        "stats": {
          "requests": "$.increment($.gS.stats.requests || 0)",
          "errors": "$.gS.stats.errors || 0"
        }
      }
    }
    
  3. Use meaningful keys:

    Good – descriptive key name that explains what is being counted:

    "userRegistrationCount": "$.increment($.gS.userRegistrationCount || 0)"
    

    Bad – generic key name that does not convey meaning:

    "count": "$.increment($.gS.count || 0)"
    
  4. Initialize default values:

    With default (recommended) – uses || 0 to start from zero if key does not exist:

    "totalUsers": "$.increment($.gS.totalUsers || 0)"
    

    Without default (risky) – may fail if the key has not been set yet:

    "totalUsers": "$.increment($.gS.totalUsers)"
    
  5. Group related data:

    "extract": {
      "cStore": {
        "order": {
          "id": "$.fake.UUIDDigit",
          "createdAt": "$.fake.RFC3339",
          "status": "created"
        },
        "customer": {
          "id": "$.req.customerId",
          "email": "$.req.email"
        }
      }
    }
    

Things to Avoid

  1. Do not store sensitive data in Stores (passwords, tokens)
  2. Do not create overly deep nesting (more than 3 levels)
  3. Do not forget about namespace isolation
  4. Do not use Stores for simple static responses
  5. Do not overload Stores with large data objects

Data Management

Cleaning Up Stale Data

{
  "id": "cleanup-stores",
  "namespace": "maintenance",
  "http": {
    "route": "/api/maintenance/cleanup"
  },
  "extract": {
    "gStore": {
      "tempData": null,
      "debugInfo": null,
      "lastCleanup": "$.fake.RFC3339",
      "cleanupCount": "$.increment($.gS.cleanupCount || 0)"
    }
  }
}

Archiving Data

{
  "id": "archive-data",
  "extract": {
    "gStore": {
      "archived": {
        "data": "$.gS.currentData",
        "archivedAt": "$.fake.RFC3339"
      },
      "currentData": null
    }
  }
}

Use Store systems to create powerful dynamic scenarios with state preservation!


See Also