Install
openclaw skills install phy-openapi-mock-serverInstant mock HTTP server from any OpenAPI 3.x or Swagger 2.0 spec. Point it at a spec file (local or URL) and get a live local server returning spec-compliant example responses — no backend code required. Wraps Stoplight Prism CLI with smart defaults. Validates the spec before starting, prints all available endpoints with example curl commands, supports validation mode (rejects non-spec requests), dynamic example selection, and auth bypass for local dev. Perfect for frontend teams blocked on a backend, contract-first API development, and integration testing without a live service. Zero external API — uses only npx and your local spec file. Triggers on "mock API", "mock server", "openapi mock", "swagger mock", "fake backend", "stub server", "contract-first", "/openapi-mock".
openclaw skills install phy-openapi-mock-serverFrontend blocked waiting for the backend? Need to test against an API that doesn't exist yet? Your spec is the source of truth — this skill turns it into a running HTTP server in one command.
Point it at any OpenAPI 3.x or Swagger 2.0 spec and get a live local mock server that returns spec-compliant responses, validates incoming requests, and shows you every available endpoint with ready-to-run curl commands.
No backend code. No Docker. No config. Just npx and your spec.
# Option 1: Local spec file
/openapi-mock openapi.yaml
/openapi-mock swagger.json
/openapi-mock api/spec/openapi.yaml
# Option 2: Spec URL (fetched once, served locally)
/openapi-mock https://petstore3.swagger.io/api/v3/openapi.json
# Option 3: Custom port
/openapi-mock openapi.yaml --port 4010
# Option 4: Validation mode (reject requests that don't match the spec)
/openapi-mock openapi.yaml --validate
# Option 5: Dynamic mode (generate random examples, not just first example)
/openapi-mock openapi.yaml --dynamic
# Option 6: Show all endpoints without starting server
/openapi-mock openapi.yaml --list
# Option 7: Mock a specific tag or path only
/openapi-mock openapi.yaml --filter /users
/openapi-mock openapi.yaml --filter tag:payments
Before starting the server, validate the spec file is syntactically correct:
# Check spec file exists and has correct extension
SPEC_FILE="$1"
if [ ! -f "$SPEC_FILE" ] && [[ "$SPEC_FILE" != http* ]]; then
echo "ERROR: Spec file not found: $SPEC_FILE"
echo "Looking for spec files in current directory..."
find . -maxdepth 3 -name "openapi.yaml" -o -name "openapi.json" \
-o -name "swagger.yaml" -o -name "swagger.json" \
-not -path "*/node_modules/*" 2>/dev/null | head -10
exit 1
fi
# Validate spec format (YAML or JSON)
if [[ "$SPEC_FILE" == *.yaml ]] || [[ "$SPEC_FILE" == *.yml ]]; then
python3 -c "import yaml,sys; yaml.safe_load(open('$SPEC_FILE'))" 2>&1 && echo "✅ YAML syntax valid" || echo "❌ YAML syntax error"
elif [[ "$SPEC_FILE" == *.json ]]; then
python3 -c "import json,sys; json.load(open('$SPEC_FILE'))" 2>&1 && echo "✅ JSON syntax valid" || echo "❌ JSON syntax error"
fi
# Check it's actually an OpenAPI/Swagger spec
python3 -c "
import yaml, json, sys
try:
with open('$SPEC_FILE') as f:
spec = yaml.safe_load(f) if '$SPEC_FILE'.endswith(('.yaml','.yml')) else json.load(f)
version = spec.get('openapi', spec.get('swagger', 'unknown'))
title = spec.get('info', {}).get('title', 'Untitled')
paths = len(spec.get('paths', {}))
print(f'✅ OpenAPI {version} | {title} | {paths} paths')
except Exception as e:
print(f'❌ Not a valid OpenAPI spec: {e}')
sys.exit(1)
"
# Check if Prism is already installed
if command -v prism &>/dev/null; then
echo "✅ Prism already installed: $(prism --version)"
elif npx --yes @stoplight/prism-cli@latest --version &>/dev/null 2>&1; then
echo "✅ Prism available via npx"
else
echo "Installing Prism..."
npm install -g @stoplight/prism-cli
# Or: yarn global add @stoplight/prism-cli
# Or: npx -p @stoplight/prism-cli prism (no install needed)
fi
Requirements: Node.js 16+ (check with node --version)
Alternative if Node.js not available:
# Docker alternative (no Node.js required)
docker run --rm -p 4010:4010 \
-v "$(pwd):/tmp/spec" \
stoplight/prism:latest \
mock /tmp/spec/openapi.yaml -h 0.0.0.0
Before starting, show all endpoints the mock server will serve:
python3 -c "
import yaml, json, sys
spec_file = '$SPEC_FILE'
with open(spec_file) as f:
spec = yaml.safe_load(f) if spec_file.endswith(('.yaml','.yml')) else json.load(f)
paths = spec.get('paths', {})
base_url = 'http://localhost:4010'
print(f'\n📋 Available Endpoints ({len(paths)} paths):')
print('=' * 60)
for path, path_item in sorted(paths.items()):
for method in ['get','post','put','patch','delete','head','options']:
op = path_item.get(method)
if not op:
continue
summary = op.get('summary', op.get('operationId', ''))
responses = list(op.get('responses', {}).keys())
print(f' {method.upper():8} {path}')
if summary:
print(f' → {summary}')
print(f' Returns: {responses}')
print()
"
PORT=${PORT:-4010}
SPEC_FILE="$1"
VALIDATE_FLAG=""
DYNAMIC_FLAG=""
# Parse options
while [[ $# -gt 1 ]]; do
case "$2" in
--validate) VALIDATE_FLAG="--validate-request" ;;
--dynamic) DYNAMIC_FLAG="--dynamic" ;;
--port) PORT="$3"; shift ;;
esac
shift
done
echo ""
echo "🚀 Starting mock server..."
echo " Spec: $SPEC_FILE"
echo " URL: http://localhost:$PORT"
echo " Mode: $([ -n "$VALIDATE_FLAG" ] && echo 'validation (rejects bad requests)' || echo 'passthrough (allows any request)')"
echo ""
# Start Prism mock server
npx --yes @stoplight/prism-cli mock "$SPEC_FILE" \
--port "$PORT" \
--host 127.0.0.1 \
$VALIDATE_FLAG \
$DYNAMIC_FLAG \
--errors
What Prism does:
example / examples values for each response → returns them verbatim"string", integer → 0, etc.)--dynamic → generates random values matching the schema on every request--validate-request → returns 422 for requests that don't match the spec's request body schemaAfter starting, output ready-to-run curl commands for every endpoint:
python3 -c "
import yaml, json
spec_file = '$SPEC_FILE'
with open(spec_file) as f:
spec = yaml.safe_load(f) if spec_file.endswith(('.yaml','.yml')) else json.load(f)
paths = spec.get('paths', {})
components = spec.get('components', {}).get('schemas', {})
base = 'http://localhost:4010'
print('\n📡 Test Commands:\n')
for path, path_item in sorted(paths.items()):
for method in ['get','post','put','patch','delete']:
op = path_item.get(method)
if not op:
continue
# Replace path params with example values
test_path = path
for param in op.get('parameters', []) + path_item.get('parameters', []):
if param.get('in') == 'path':
example = param.get('example', param.get('schema', {}).get('example', '1'))
test_path = test_path.replace('{' + param['name'] + '}', str(example))
# Build query string for GET
query_params = []
if method == 'get':
for param in op.get('parameters', []):
if param.get('in') == 'query' and param.get('required'):
example = param.get('example', param.get('schema', {}).get('example', 'value'))
query_params.append(f'{param[\"name\"]}={example}')
url = f'{base}{test_path}'
if query_params:
url += '?' + '&'.join(query_params)
# Build request body hint for POST/PUT/PATCH
body_hint = ''
req_body = op.get('requestBody', {})
if req_body and method in ['post', 'put', 'patch']:
body_hint = \" -H 'Content-Type: application/json' -d '{}'\"
summary = op.get('summary', '')
print(f'# {summary}' if summary else '')
print(f'curl -s -X {method.upper()} \"{url}\"{body_hint} | python3 -m json.tool')
print()
"
## Mock Server Ready
Spec: openapi.yaml (OpenAPI 3.0.3 — Petstore API)
Server: http://localhost:4010
Mode: Passthrough (use --validate to reject invalid requests)
---
### Available Endpoints (12 total)
| Method | Path | Summary | Returns |
|--------|------|---------|---------|
| GET | /pets | List all pets | 200, 400 |
| POST | /pets | Create a pet | 201, default |
| GET | /pets/{petId} | Info for a specific pet | 200, default |
| DELETE | /pets/{petId} | Delete a pet | 204, default |
| GET | /users | List users | 200 |
| POST | /users | Create user | 201, 409 |
| GET | /users/{id} | Get user by ID | 200, 404 |
| PUT | /users/{id} | Update user | 200, 404, 422 |
---
### Quick Test Commands
```bash
# List all pets
curl -s -X GET "http://localhost:4010/pets" | python3 -m json.tool
# Get specific pet
curl -s -X GET "http://localhost:4010/pets/1" | python3 -m json.tool
# Create a pet (replace {} with actual body)
curl -s -X POST "http://localhost:4010/pets" \
-H "Content-Type: application/json" \
-d '{"name": "Buddy", "tag": "dog"}' | python3 -m json.tool
# Test a 404 response
curl -s -X GET "http://localhost:4010/pets/99999" | python3 -m json.tool
# → Prism returns the spec's 'default' response example
# Test validation mode rejection
curl -s -X POST "http://localhost:4010/pets" \
-H "Content-Type: application/json" \
-d '{"invalid_field": true}' | python3 -m json.tool
# → Returns 422 with validation error details
Force a specific response code:
# Tell Prism which response code to return via header
curl -H "Prefer: code=404" http://localhost:4010/pets/1
curl -H "Prefer: code=500" http://localhost:4010/pets/1
Force dynamic example generation:
curl -H "Prefer: dynamic=true" http://localhost:4010/pets
# → Returns random values matching the schema on every request
Test auth-protected endpoints (bypass in local dev):
# Prism doesn't enforce auth by default — just send the header
curl -H "Authorization: Bearer fake-token-for-local-dev" http://localhost:4010/users/me
| Problem | Cause | Fix |
|---|---|---|
Error: Cannot read property 'responses' | Spec has invalid path | Check yaml syntax around that path |
422 Request body invalid | --validate mode on, bad request | Either fix your request or remove --validate for dev |
Empty response body {} | No example in spec for that field | Add example: values to your spec, or use --dynamic |
| Port 4010 in use | Another process | Use --port 4011 |
npx: command not found | Node.js not installed | Install Node.js 16+ or use the Docker alternative |
---
## Advanced: Adding Examples to Your Spec
Prism returns the best response when your spec has `example` values. If responses look empty:
```yaml
# Before (no examples — Prism returns minimal defaults)
paths:
/users/{id}:
get:
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/User'
# After (Prism returns this exact object)
paths:
/users/{id}:
get:
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/User'
example:
id: "usr_abc123"
email: "alice@example.com"
name: "Alice Smith"
created_at: "2026-01-15T10:30:00Z"
The full parallel-development workflow this skill enables:
Day 1: Team agrees on API contract → openapi.yaml committed to repo
↓
Backend team: implements real API
Frontend team: /openapi-mock openapi.yaml → developing against mock server
Day 14: Backend is ready
Frontend: Change API_BASE_URL from http://localhost:4010 to https://api.yourapp.com
→ Integration works immediately (both sides built to the same contract)
# In your frontend .env.local
NEXT_PUBLIC_API_URL=http://localhost:4010 # Mock during dev
# NEXT_PUBLIC_API_URL=https://api.prod.com # Uncomment for production
If you prefer a binary over npx:
# Install Mockoon CLI
npm install -g @mockoon/cli
# Start mock server from OpenAPI spec
mockoon-cli start --data openapi.yaml --port 4010
# Or use the Mockoon GUI to visually edit mock responses
# → Export as Mockoon data file → then use CLI
| Tool | Approach | Best For |
|---|---|---|
| Prism (this skill) | CLI, OpenAPI-native, spec-driven | Contract-first teams, CI validation |
| Mockoon | GUI + CLI, visual editor | Teams who want to hand-edit mock responses |
| MSW | In-browser/Node service worker | Unit/integration tests in JS — not a real HTTP server |
| WireMock | Java, powerful but heavy | Enterprise teams, complex stateful mocks |
| json-server | REST from JSON file | Simple CRUD prototypes (no spec enforcement) |
This skill covers the most common case: you have a spec, you need a server, you need it now.
Canlah AI — Run performance marketing without breaking your brand.