Store Systems в Mockarty
Содержание
- Обзор Store систем
- Mock Store (MStore)
- Chain Store (CStore)
- Global Store (GStore)
- API для управления Store
- Примеры использования
- Лучшие практики
Совет: Примеры кода доступны для cURL, CLI и SDK-клиентов (Go, Python, Java). Смотрите Руководство по SDK для установки и настройки. Смотрите Руководство по CLI для командной утилиты.
URL-адреса в примерах: Во всех примерах используется
localhost:5770как адрес Mockarty по умолчанию. Если ваш экземпляр работает на удалённом сервере, заменитеlocalhost:5770на реальный адрес (например,https://mockarty.company.comилиhttp://192.168.1.50:5770). Подробнее — в разделе Полезные функции и советы.
Обзор Store систем
Ключевые понятия для начинающих
Прежде чем углубляться в Store-системы, вот несколько ключевых терминов:
- Мок – имитация API-эндпоинта, которая возвращает заранее заданные ответы вместо обращения к реальному сервису.
- Namespace (пространство имён) – логическая группировка моков (как папка). Моки в разных пространствах имён изолированы друг от друга.
- Chain (цепочка) – последовательность связанных моков, которые разделяют состояние. Например, «создать заказ» -> «оплатить заказ» -> «отправить заказ» образуют цепочку.
- Extract (извлечение) – процесс извлечения данных из запроса (или генерации данных) и сохранения их в хранилище для последующего использования.
- JsonPath – язык запросов (например,
$.mS.userId) для обращения к сохранённым значениям в ответах моков.
Какой Store выбрать
Не уверены, какое хранилище использовать? Вот простое руководство:
- Mock Store (mS) – Используйте, когда нужны временные данные в рамках одного вызова мока. Пример: сгенерировать UUID и использовать его в нескольких местах одного ответа. Данные исчезают после обработки запроса.
- Chain Store (cS) – Используйте, когда нужно передавать данные между связанными моками, образующими рабочий процесс. Пример: процесс регистрации пользователя, где мок регистрации сохраняет userId, а мок профиля его считывает. Данные сохраняются между вызовами в рамках одной цепочки.
- Global Store (gS) – Используйте, когда нужно общее состояние для всех моков в пространстве имён. Пример: счётчики запросов, feature-флаги или системные настройки. Данные сохраняются бессрочно до явной очистки.
Концепция Store
Store - это системы хранения данных в Mockarty, которые позволяют:
- Сохранять данные между вызовами моков
- Обмениваться данными между связанными моками
- Аккумулировать состояние для сложных сценариев
- Создавать динамические ответы на основе накопленных данных с помощью JsonPath и Faker
Архитектура Store
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
| Store Type | Область видимости | Время жизни | Namespace | JsonPath доступ |
|---|---|---|---|---|
| MStore | Локальный мок | Во время обработки мока | N/A | $.mS.key |
| CStore | Все моки в Chain | Постоянный | ✅ | $.cS.key |
| GStore | Все моки в Namespace | Постоянный | ✅ | $.gS.key |
Интерфейс управления хранилищами
Страница Stores в веб-интерфейсе Mockarty предоставляет визуальный интерфейс для просмотра и управления всеми тремя типами хранилищ. Используйте вкладки вверху для переключения между Global Store, Chain Store и Mock Store.

Примечание: Запись в хранилища из extract-операций выполняется асинхронно. Значения могут быть недоступны мгновенно при одновременных запросах.
Mock Store (MStore)
Что такое Mock Store?
Mock Store (MStore) - это локальное хранилище данных для конкретного мока, доступное только во время обработки этого мока.

Особенности:
- Изоляция – данные доступны только внутри конкретного мока
- Временность – данные живут только во время обработки запроса
- Быстрота – хранится в памяти мока
- Простота – не требует управления namespace или chainId
Использование MStore
Извлечение в 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)"
}
}
}
Доступ к MStore в ответе
{
"response": {
"payload": {
"userId": "$.mS.generatedId",
"processedAt": "$.mS.requestTime",
"metadata": {
"clientIP": "$.mS.clientIP",
"userAgent": "$.mS.userAgent",
"requestCount": "$.mS.requestCount"
}
}
}
}
Типичные случаи использования MStore
-
Генерация связанных ID:
"extract": { "mStore": { "userId": "$.fake.UUIDDigit", "profileId": "$.fake.UUIDDigit", "sessionId": "$.fake.UUID" } } -
Обработка метаданных запроса:
"extract": { "mStore": { "timestamp": "$.fake.RFC3339", "requestId": "$.fake.UUID", "traceId": "$.reqHeader['X-Trace-ID'][0]" } } -
Математические вычисления:
"extract": { "mStore": { "basePrice": "$.req.price", "tax": "$.multiply($.req.price, 0.2)", "totalPrice": "$.sum($.req.price, $.mS.tax)" } }
Chain Store (CStore)
Что такое Chain Store?
Chain Store (CStore) - это разделяемое хранилище данных между всеми моками с одинаковым chainId в рамках одного namespace.

Особенности:
- Разделяемость – данные доступны всем мокам в цепочке
- Персистентность – данные сохраняются между вызовами
- Namespace изоляция – данные изолированы по namespace
- Аккумуляция – данные накапливаются по мере выполнения цепочки
Жизненный цикл CStore
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)
Использование CStore
Начальный мок в цепочке
{
"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"
}
}
}
Промежуточный мок в цепочке
{
"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"
}
}
}
Финальный мок в цепочке
{
"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
}
}
}
API для Chain Store
Получение данных Chain Store
GET /api/v1/stores/chain/{chainId}?namespace=e-commerce
Добавление данных в Chain Store
Каждый запрос добавляет одну пару ключ-значение. Для добавления неск��льких записей выполните отдельные запросы для каждого ключа.
POST /api/v1/stores/chain/order-processing
Content-Type: application/json
{
"key": "manualStep",
"value": "admin-review",
"namespace": "e-commerce"
}
Удаление данных из Chain Store
Удаление одного ключа через URL-путь:
DELETE /api/v1/stores/chain/order-processing/temporaryData?namespace=e-commerce
Global Store (GStore)
Что такое Global Store?
Global Store (GStore) - это глобальное хранилище данных, доступное всем мокам в рамках одного namespace.

Особенности:
- Глобальность – данные доступны всем мокам в namespace
- Персистентность – данные сохраняются между всеми вызовами
- Namespace изоляция – данные изолированы по namespace
- Аккумуляция – идеально для счетчиков и статистики
Использование GStore
Счетчики и статистика
{
"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]"
}
}
}
Системные настройки
{
"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"
}
}
}
Глобальные состояния
{
"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"
}
}
}
API для Global Store
Получение данных Global Store
GET /api/v1/stores/global?namespace=monitoring
Добавление данных в Global Store
Каждый запрос добавляет одну пару ключ-значение. Для добавления нескольких записей выполните отдельные запросы для каждого ключа.
POST /api/v1/stores/global
Content-Type: application/json
{
"key": "systemVersion",
"value": "1.2.3",
"namespace": "monitoring"
}
Удаление данных из Global Store
Удаление одного ключа через URL-путь:
DELETE /api/v1/stores/global/oldConfig?namespace=monitoring
API для управления Store
Полная справка API
Полную документацию API см. в Справочнике API.
Global Store Endpoints
| Method | Endpoint | Описание |
|---|---|---|
| GET | /api/v1/stores/global |
Получить Global Store |
| POST | /api/v1/stores/global |
Добавить пару ключ-значение в Global Store |
| DELETE | /api/v1/stores/global/{key} |
Удалить ключ из Global Store |
Query Parameters:
namespace(optional) - пространство (default: “sandbox”)
POST Body: {"key": "...", "value": "...", "namespace": "..."}
Chain Store Endpoints
| Method | Endpoint | Описание |
|---|---|---|
| GET | /api/v1/stores/chain/{chainId} |
Получить Chain Store |
| POST | /api/v1/stores/chain/{chainId} |
Добавить пару ключ-значение в Chain Store |
| DELETE | /api/v1/stores/chain/{chainId}/{key} |
Удалить ключ из Chain Store |
Path Parameters:
chainId- ID цепочкиkey- удаляемый ключ (только для DELETE)
Query Parameters:
namespace(optional) - пространство (default: “sandbox”)
POST Body: {"key": "...", "value": "...", "namespace": "..."}
Примеры API вызовов
Добавление в Global Store
Каждый вызов API добавляет одну пару ключ-значение. Для нескольких ключей выполните отдельные запросы.
cURL
# Добавить пару ключ-значение в 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"}'
# Добавить ещё один ключ
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 задаётся при создании клиента (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 задаётся при создании клиента (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");
Добавление в 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");
Удаление данных из Store
Удаление одного ключа за запрос через URL-путь.
cURL
# Удалить ключ из Global Store
curl -X DELETE http://localhost:5770/api/v1/stores/global/tempData?namespace=testing
# Удалить ключ из Chain Store
curl -X DELETE http://localhost:5770/api/v1/stores/chain/user-journey/debugData?namespace=testing
CLI
# Удалить ключ из Global Store
mockarty-cli store global delete --namespace testing --key tempData
# Удалить ключ из Chain Store
mockarty-cli store chain delete user-journey --namespace testing --key debugData
Go
// Удалить ключ из Global Store
err := client.Stores().GlobalDelete(ctx, "testing", "tempData")
// Удалить ключ из Chain Store
err = client.Stores().ChainDelete(ctx, "user-journey", "testing", "debugData")
Python
# Удалить ключ из Global Store
client.stores.global_delete(namespace="testing", key="tempData")
# Удалить ключ из Chain Store
client.stores.chain_delete(chain_id="user-journey", namespace="testing", key="debugData")
Java
// Удалить ключ из Global Store
client.stores().globalDelete("testing", "tempData");
// Удалить ключ из Chain Store
client.stores().chainDelete("user-journey", "testing", "debugData");
Примеры использования
В предыдущих разделах уже показаны базовые паттерны для каждого типа хранилища – счётчики, конфигурация и цепочки моков. Примеры ниже демонстрируют более сложные сценарии, которые комбинируют несколько типов Store или показывают межхранилищное взаимодействие.
Сложные Chain сценарии
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"
}
}
}
Отслеживание экспериментов с Store
Отслеживание назначений экспериментов
{
"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"
}
}
}
Лучшие практики
Рекомендации
-
Используйте правильный тип Store для задач:
- MStore - для временных вычислений внутри мока
- CStore - для передачи данных между этапами сценария
- GStore - для глобальных счетчиков и настроек
-
Структурируйте данные в Store:
"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" } } } -
Используйте осмысленные ключи:
Хорошо – описательное имя ключа, объясняющее что считается:
"userRegistrationCount": "$.increment($.gS.userRegistrationCount || 0)"Плохо – общее имя ключа, не несущее смысла:
"count": "$.increment($.gS.count || 0)" -
Инициализируйте значения по умолчанию:
С default (рекомендуется) – использует
|| 0для старта с нуля, если ключ не существует:"totalUsers": "$.increment($.gS.totalUsers || 0)"Без default (рискованно) – может завершиться ошибкой, если ключ ещё не был установлен:
"totalUsers": "$.increment($.gS.totalUsers)" -
Группируйте связанные данные:
"extract": { "cStore": { "order": { "id": "$.fake.UUIDDigit", "createdAt": "$.fake.RFC3339", "status": "created" }, "customer": { "id": "$.req.customerId", "email": "$.req.email" } } }
Что избегать
- Не храните чувствительные данные в Store (пароли, токены)
- Не создавайте слишком глубокие вложенности (>3 уровней)
- Не забывайте про namespace изоляцию
- Не используйте Store для простых статических ответов
- Не переполняйте Store большими объектами данных
Управление данными
Очистка устаревших данных
{
"id": "cleanup-stores",
"namespace": "maintenance",
"http": {
"route": "/api/maintenance/cleanup"
},
"extract": {
"gStore": {
"tempData": null,
"debugInfo": null,
"lastCleanup": "$.fake.RFC3339",
"cleanupCount": "$.increment($.gS.cleanupCount || 0)"
}
}
}
Архивация данных
{
"id": "archive-data",
"extract": {
"gStore": {
"archived": {
"data": "$.gS.currentData",
"archivedAt": "$.fake.RFC3339"
},
"currentData": null
}
}
}
Используйте Store системы для создания мощных динамических сценариев с сохранением состояния!
Смотрите также
- Руководство по JsonPath – язык запросов для доступа и манипуляции данными Store
- Справочник Faker-функций – генерация случайных данных для заполнения Store
- Справочник API – полный REST API для управления Store
- Руководство по веб-интерфейсу – управление Store через веб-интерфейс
- Вебхуки и обратные вызовы – использование данных Store в webhook-ах