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

Store Systems Overview

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[Session]
        PERMANENT[Permanent]
        NAMESPACE_ISOLATED[Namespace Isolated]
    end

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

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

    classDef store fill:#e3f2fd
    classDef scope fill:#f3e5f5
    classDef persistence fill:#e8f5e8

    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

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.

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]",
      "requestSize": "$.length($.req)"
    }
  }
}

Accessing MStore in the Response

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

Typical MStore Use Cases

  1. Generating related IDs:

    "extract": {
      "mStore": {
        "userId": "$.fake.UUIDDigit",
        "profileId": "$.concat('profile-', $.fake.UUIDDigit)",
        "sessionId": "$.fake.UUID"
      }
    }
    
  2. Processing request metadata:

    "extract": {
      "mStore": {
        "timestamp": "$.fake.RFC3339",
        "requestHash": "$.hash($.req)",
        "contentLength": "$.length($.req)"
      }
    }
    
  3. Conditional computations:

    "extract": {
      "mStore": {
        "discountPercent": "$.req.isVip ? 0.2 : 0.1",
        "finalPrice": "$.multiply($.req.price, $.subtract(1, $.mS.discountPercent))"
      }
    }
    

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.

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": "$.sum($.req.items[*].price)",
      "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.Zip",
      "estimatedDelivery": "$.fake.FutureDate",
      "orderSummary": {
        "items": "$.cS.items",
        "totalAmount": "$.cS.totalAmount",
        "createdAt": "$.cS.createdAt",
        "paidAt": "$.cS.paidAt",
        "fulfilledAt": "$.fake.RFC3339"
      }
    }
  },
  "extract": {
    "cStore": {
      "trackingNumber": "$.fake.Zip",
      "fulfilledAt": "$.fake.RFC3339",
      "currentStep": "fulfilled",
      "isComplete": true
    }
  }
}

Chain Store API

Retrieving Chain Store Data

GET /mock/store/chain/{chainId}?namespace=e-commerce

Adding Data to Chain Store

POST /mock/store/chain/order-processing?namespace=e-commerce
Content-Type: application/json

{
  "manualStep": "admin-review",
  "reviewedBy": "admin-123",
  "reviewedAt": "2024-01-01T15:00:00Z"
}

Deleting Data from Chain Store

DELETE /mock/store/chain/order-processing?namespace=e-commerce
Content-Type: application/json

{
  "keys": ["temporaryData", "debugInfo"]
}

Global Store (GStore)

What is Global Store?

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

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",
      "uniqueUsers": "$.addToSet($.gS.uniqueUsers || [], $.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/:featureName"
  },
  "response": {
    "payload": {
      "feature": "$.pathParam.featureName",
      "enabled": "$.gS.features[$.pathParam.featureName].enabled",
      "config": "$.gS.features[$.pathParam.featureName].config",
      "rolloutPercentage": "$.gS.features[$.pathParam.featureName].rollout"
    }
  },
  "extract": {
    "gStore": {
      "featureAccessCount": {
        "$.pathParam.featureName": "$.increment($.gS.featureAccessCount[$.pathParam.featureName] || 0)"
      },
      "lastFeatureAccess": "$.fake.RFC3339"
    }
  }
}

Global Store API

Retrieving Global Store Data

GET /mock/store/global?namespace=monitoring

Adding Data to Global Store

POST /mock/store/global?namespace=monitoring
Content-Type: application/json

{
  "systemVersion": "1.2.3",
  "maintenanceMode": false,
  "enabledFeatures": ["feature-a", "feature-b"],
  "configLastUpdated": "2024-01-01T12:00:00Z"
}

Deleting Data from Global Store

DELETE /mock/store/global?namespace=monitoring
Content-Type: application/json

{
  "keys": ["oldConfig", "deprecatedFeature"]
}

Store Management API

Full API Reference

For the complete API documentation, see the API Reference.

Global Store Endpoints

Method Endpoint Description
GET /mock/store/global Get Global Store
POST /mock/store/global Add data to Global Store
DELETE /mock/store/global Delete keys from Global Store

Query Parameters:

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

Chain Store Endpoints

Method Endpoint Description
GET /mock/store/chain/{chainId} Get Chain Store
POST /mock/store/chain/{chainId} Add data to Chain Store
DELETE /mock/store/chain/{chainId} Delete keys from Chain Store

Path Parameters:

  • chainId – chain ID

Query Parameters:

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

API Call Examples

Initializing Global Store

curl -X POST http://localhost:5770/mock/store/global?namespace=testing \
  -H "Content-Type: application/json" \
  -d '{
    "systemStats": {
      "totalRequests": 0,
      "totalUsers": 0,
      "totalErrors": 0
    },
    "features": {
      "newUI": {"enabled": true, "rollout": 100},
      "betaFeature": {"enabled": false, "rollout": 0}
    },
    "config": {
      "version": "1.0.0",
      "environment": "testing"
    }
  }'

Initializing Chain Store

curl -X POST http://localhost:5770/mock/store/chain/user-journey?namespace=testing \
  -H "Content-Type: application/json" \
  -d '{
    "journeyStarted": true,
    "startTime": "2024-01-01T10:00:00Z",
    "steps": [],
    "currentStep": 0
  }'

Clearing Store Data

# Clear specific keys from Global Store
curl -X DELETE http://localhost:5770/mock/store/global?namespace=testing \
  -H "Content-Type: application/json" \
  -d '{"keys": ["tempData", "debugInfo"]}'

# Clear specific keys from Chain Store
curl -X DELETE http://localhost:5770/mock/store/chain/user-journey?namespace=testing \
  -H "Content-Type: application/json" \
  -d '{"keys": ["tempStep", "debugData"]}'

Usage Examples

Counters and Metrics

Global API Request Counter

{
  "id": "api-metrics",
  "namespace": "monitoring",
  "http": {
    "route": "/api/metrics/increment"
  },
  "response": {
    "payload": {
      "totalRequests": "$.gS.totalRequests",
      "requestsThisHour": "$.gS.requestsThisHour",
      "averageResponseTime": "$.gS.avgResponseTime",
      "errorRate": "$.gS.errorRate"
    }
  },
  "extract": {
    "gStore": {
      "totalRequests": "$.increment($.gS.totalRequests || 0)",
      "requestsThisHour": "$.increment($.gS.requestsThisHour || 0)",
      "lastRequestTime": "$.fake.RFC3339"
    }
  }
}

User Sessions

{
  "id": "user-session",
  "namespace": "sessions",
  "http": {
    "route": "/api/users/session"
  },
  "response": {
    "payload": {
      "userId": "$.req.userId",
      "sessionId": "$.fake.UUID",
      "activeSessions": "$.gS.activeSessions",
      "totalSessions": "$.gS.totalSessions"
    }
  },
  "extract": {
    "gStore": {
      "activeSessions": "$.addToSet($.gS.activeSessions || [], $.req.userId)",
      "totalSessions": "$.increment($.gS.totalSessions || 0)",
      "lastActivity": "$.fake.RFC3339"
    }
  }
}

System State

Feature Flags

{
  "id": "feature-flags",
  "namespace": "features",
  "http": {
    "route": "/api/features"
  },
  "response": {
    "payload": {
      "features": {
        "newDashboard": "$.gS.features.newDashboard",
        "advancedSearch": "$.gS.features.advancedSearch",
        "betaEditor": "$.gS.features.betaEditor"
      },
      "userSegment": "$.req.segment",
      "rolloutConfig": "$.gS.rolloutConfig"
    }
  },
  "extract": {
    "gStore": {
      "featureRequests": "$.increment($.gS.featureRequests || 0)",
      "lastFeatureCheck": "$.fake.RFC3339"
    }
  }
}

System Health

{
  "id": "system-health",
  "namespace": "monitoring",
  "http": {
    "route": "/api/health/detailed"
  },
  "response": {
    "payload": {
      "status": "$.gS.systemStatus",
      "uptime": "$.gS.systemUptime",
      "services": {
        "database": "$.gS.services.database",
        "redis": "$.gS.services.redis",
        "api": "$.gS.services.api"
      },
      "metrics": {
        "requestCount": "$.gS.totalRequests",
        "errorCount": "$.gS.totalErrors",
        "averageResponseTime": "$.gS.avgResponseTime"
      }
    }
  },
  "extract": {
    "gStore": {
      "healthCheckCount": "$.increment($.gS.healthCheckCount || 0)",
      "lastHealthCheck": "$.fake.RFC3339"
    }
  }
}

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": {
        "completed": "$.append($.cS.steps, 'manager-approved')",
        "remaining": "$.cS.approvalChain[1:]",
        "percentage": 33
      }
    }
  },
  "extract": {
    "cStore": {
      "managerApprovedBy": "$.req.approverId",
      "managerApprovedAt": "$.fake.RFC3339",
      "currentStep": "manager-approved",
      "steps": "$.append($.cS.steps, 'manager-approved')"
    }
  }
}

A/B Testing with Stores

Variant Assignment

{
  "id": "ab-test-assignment",
  "namespace": "experiments",
  "http": {
    "route": "/api/experiment/assign"
  },
  "response": {
    "payload": {
      "userId": "$.req.userId",
      "experiment": "new-checkout-flow",
      "variant": "$.hash($.req.userId) % 2 == 0 ? 'A' : 'B'",
      "assignedAt": "$.fake.RFC3339"
    }
  },
  "extract": {
    "gStore": {
      "experiments": {
        "new-checkout-flow": {
          "totalAssignments": "$.increment($.gS.experiments['new-checkout-flow'].totalAssignments || 0)",
          "variantA": "$.hash($.req.userId) % 2 == 0 ? $.increment($.gS.experiments['new-checkout-flow'].variantA || 0) : $.gS.experiments['new-checkout-flow'].variantA",
          "variantB": "$.hash($.req.userId) % 2 != 0 ? $.increment($.gS.experiments['new-checkout-flow'].variantB || 0) : $.gS.experiments['new-checkout-flow'].variantB"
        }
      }
    }
  }
}

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
    "userRegistrationCount": "$.increment($.gS.userRegistrationCount || 0)"
    
    // Bad
    "count": "$.increment($.gS.count || 0)"
    
  4. Initialize default values:

    "totalUsers": "$.increment($.gS.totalUsers || 0)"    // With default
    "totalUsers": "$.increment($.gS.totalUsers)"         // Without default
    
  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