Frontend 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
curl -s -X GET "http://localhost:4010/pets" | python3 -m json.tool
curl -s -X GET "http://localhost:4010/pets/1" | python3 -m json.tool
curl -s -X POST "http://localhost:4010/pets" \
-H "Content-Type: application/json" \
-d '{"name": "Buddy", "tag": "dog"}' | python3 -m json.tool
curl -s -X GET "http://localhost:4010/pets/99999" | python3 -m json.tool
curl -s -X POST "http://localhost:4010/pets" \
-H "Content-Type: application/json" \
-d '{"invalid_field": true}' | python3 -m json.tool
---
### Tips
**Force a specific response code:**
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
**Test auth-protected endpoints (bypass in local dev):**
curl -H "Authorization: Bearer fake-token-for-local-dev" http://localhost:4010/users/me
---
### Troubleshooting
| 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 |
Prism returns the best response when your spec has example values. If responses look empty:
# 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.
共 1 个版本