MockServiceInGo is an API mocking service for development and testing.
It lets you register mock routes at runtime and return HTTP, SSE, or WebSocket responses without changing application code.
- Dynamic mock registration via HTTP API
- File-based rule persistence with periodic autosave
- Config upload endpoint to load many rules at once
- Distributed deployment mode using Raft for rule replication
- Optional React UI for managing routes (
frontend/MockService)
- Distributed deployment is implemented (Raft-based replication across nodes).
- Built-in tenant-isolated storage is not implemented yet (roadmap item).
- Current workaround: use tenant prefixes in paths (for example
/t/acme/orders) or run one service instance per tenant.
- Current workaround: use tenant prefixes in paths (for example
backend/: Go service and Raft implementationfrontend/MockService/: optional React UIbackend/integrate_test/: example standalone and cluster configs/scripts
- Go
1.25.x(module inbackend/go.mod) - Optional for UI: Node.js + npm
From project root:
cd backend
go run ./cmd/starter -config ./integrate_test/start-standalone.jsonService starts on :9900 using the sample standalone config.
Health check:
curl -s http://127.0.0.1:9900/v1/healthBase API prefix: /v1
GET /v1/healthPOST /v1/__mockPOST /v1/__mock/upload(multipart form file field name must beconfig.json)GET /v1/__mockDELETE /v1/__mock/allDELETE /v1/__mock/:method?path=/your/path
All unmatched routes are handled by the mock matcher (NoRoute), so requests to registered paths return configured mock responses.
curl -X POST http://127.0.0.1:9900/v1/__mock \
-H "Content-Type: application/json" \
-d '{
"method": "GET",
"path": "/api/orders",
"status": 200,
"responseHeaders": {
"Content-Type": "application/json",
"X-Mock": "true"
},
"responseBody": "{\"items\":[{\"id\":1}]}"
}'Test it:
curl -i http://127.0.0.1:9900/api/orderscurl -X POST http://127.0.0.1:9900/v1/__mock \
-H "Content-Type: application/json" \
-d '{
"method": "GET",
"path": "/stream/events",
"responseType": "sse",
"sseEvents": [
{ "event": "tick", "data": "one", "delay": 1000000000 },
{ "event": "tick", "data": "two", "delay": 1000000000 }
]
}'Notes:
delayuses Go duration JSON encoding (time.Duration, nanoseconds).
1000000000=1s.
curl -X POST http://127.0.0.1:9900/v1/__mock \
-H "Content-Type: application/json" \
-d '{
"method": "GET",
"path": "/ws/demo",
"responseType": "websocket",
"websocketMessages": [
{ "message": "hello", "delay": 500000000, "type": "text" },
{ "message": "world", "delay": 500000000, "type": "text" }
]
}'Notes:
- For WebSocket mocks, server-side logic enforces
GETfor upgrade requests.
Upload a JSON file containing an array of rules:
curl -X POST http://127.0.0.1:9900/v1/__mock/upload \
-F "config.json=@./config_upload_test.json"- Rules are loaded from
rulesFileat startup (if file exists). - Rules are auto-saved approximately every 2 seconds.
- In distributed mode, rule mutations are replicated through Raft.
Sample 3-node configs:
backend/integrate_test/start1.json(service:9000, raft127.0.0.1:8081)backend/integrate_test/start2.json(service:9001, raft127.0.0.1:8082)backend/integrate_test/start3.json(service:9002, raft127.0.0.1:8083)
Start cluster:
cd backend/integrate_test
./start_cluster.shStop cluster:
cd backend/integrate_test
./stop.shManual start option:
cd backend
go run ./cmd/starter -config ./integrate_test/start1.json
go run ./cmd/starter -config ./integrate_test/start2.json
go run ./cmd/starter -config ./integrate_test/start3.jsonCluster behavior notes:
- Writes must be accepted by the current leader to replicate.
- Followers may reject writes during leadership mismatch/election windows.
- After leader election settles, successful writes propagate to all nodes.
From project root:
cd frontend/MockService
npm install
npm run devOther scripts:
npm run build
npm run test
npm run lintUI expects backend API to be running.
Backend:
cd backend
go test ./...Frontend:
cd frontend/MockService
npm run test
npm run lintconfig file is required: startstarterwith-config.- Port bind errors: update
serviceAddr/raft.addressin config JSON files. - Cluster write conflicts: retry after election; ensure request targets leader node.
- Missing responses: verify request method + path exactly match registered rule.