Docs
Mock Server Setup Tutorial
Learn how to build and configure mock API servers with Quadrastack for local development and testing without external dependencies.
Mock Server Setup Tutorial
Learn how to create mock API servers directly in your test playbooks. No external tools required - everything is defined in YAML.
Time: 20 minutes | Level: Intermediate
What You'll Build
A complete mock API server with:
- Multiple endpoints (GET, POST, PUT, DELETE)
- Path parameters and dynamic routing
- Request matching (headers, body, query params)
- Response sequences
- Multiple mock servers running simultaneously
Prerequisites
- Completed First API Test tutorial
- Understanding of REST APIs
- 20 minutes
Why Use Mock Servers?
Mock servers are essential for:
- Local Development - Test without internet or real APIs
- Controlled Testing - Simulate specific scenarios (errors, edge cases)
- Faster Tests - No network latency
- Team Collaboration - Share reproducible test environments
- Offline Work - Develop and test anywhere
Step 1: Create Your First Mock Server
Create a new directory:
mkdir mock-server-tutorial
cd mock-server-tutorial
Create mocks.yaml:
mockServer:
my-api:
description: My first mock API
listen: ":8080"
mocks:
hello-world:
server: my-api
description: Simple hello world endpoint
match:
method: GET
path: /hello
respond:
- status: 200
body: |
{
"message": "Hello, World!"
}
Start the mock server:
quadrastack --mock-server my-api
Expected Output:
Mock server 'my-api' started on :8080
Registered routes:
GET /hello
Press Ctrl+C to stop
Test it with curl:
curl http://localhost:8080/hello
Response:
{
"message": "Hello, World!"
}
Step 2: Add Multiple HTTP Methods
Expand mocks.yaml to support CRUD operations:
mockServer:
my-api:
description: CRUD API mock server
listen: ":8080"
defaults:
status: 200
headers:
Content-Type: application/json
mocks:
list-users:
server: my-api
description: Get all users
match:
method: GET
path: /api/users
respond:
- body: |
[
{
"id": "1",
"name": "Alice Johnson",
"email": "alice@example.com"
},
{
"id": "2",
"name": "Bob Smith",
"email": "bob@example.com"
}
]
create-user:
server: my-api
description: Create new user
match:
method: POST
path: /api/users
respond:
- status: 201
body: |
{
"id": "3",
"name": "New User",
"email": "new@example.com",
"createdAt": "2024-01-01T00:00:00Z"
}
get-user:
server: my-api
description: Get single user by ID (Dynamic Response)
match:
method: GET
path: /api/users/{id}
respond:
- body: |
{
"id": "{id}",
"name": "User {id}",
"email": "user{id}@example.com"
}
update-user:
server: my-api
description: Update existing user
match:
method: PUT
path: /api/users/{id}
respond:
- body: |
{
"id": "{id}",
"name": "Updated User",
"email": "updated@example.com",
"updatedAt": "2024-01-01T00:00:00Z"
}
delete-user:
server: my-api
description: Delete user
match:
method: DELETE
path: /api/users/{id}
respond:
- status: 204
Restart your mock server and test:
# List users
curl http://localhost:8080/api/users
# Get specific user (notice {id} is replaced)
curl http://localhost:8080/api/users/42
# Create user
curl -X POST http://localhost:8080/api/users \
-H "Content-Type: application/json" \
-d '{"name":"Jane","email":"jane@example.com"}'
# Update user
curl -X PUT http://localhost:8080/api/users/1 \
-H "Content-Type: application/json" \
-d '{"name":"Updated Jane"}'
# Delete user
curl -X DELETE http://localhost:8080/api/users/1
Step 3: Advanced Request Matching
Match requests based on headers, query parameters, and body content:
mocks:
auth-required:
server: my-api
description: Endpoint requiring authentication
match:
method: GET
path: /api/protected
headers:
Authorization: "Bearer secret-token"
respond:
- body: |
{
"message": "Access granted",
"user": "authenticated-user"
}
auth-missing:
server: my-api
description: Handle missing authentication
match:
method: GET
path: /api/protected
respond:
- status: 401
body: |
{
"error": "Unauthorized",
"message": "Authentication required"
}
search-users:
server: my-api
description: Search with query parameters
match:
method: GET
path: /api/users/search
query:
role: "admin"
respond:
- body: |
[
{
"id": "1",
"name": "Admin User",
"role": "admin"
}
]
create-with-validation:
server: my-api
description: Validate request body fields
match:
method: POST
path: /api/users
body:
$.email: contains "@"
respond:
- status: 201
body: |
{
"id": "new-id",
"message": "User created with valid email"
}
create-invalid-email:
server: my-api
description: Reject invalid email
match:
method: POST
path: /api/users
respond:
- status: 400
body: |
{
"error": "Invalid email format"
}
Test the matching:
# Success with token
curl http://localhost:8080/api/protected \
-H "Authorization: Bearer secret-token"
# Fail without token
curl http://localhost:8080/api/protected
# Search with query
curl "http://localhost:8080/api/users/search?role=admin"
Step 4: Response Sequences
Simulate changing state with response sequences:
mocks:
polling-endpoint:
server: my-api
description: Endpoint that changes over time
match:
method: GET
path: /api/job/status
respond:
- status: 200
body: |
{
"status": "pending",
"progress": 0
}
count: 2
- status: 200
body: |
{
"status": "processing",
"progress": 50
}
count: 3
- status: 200
body: |
{
"status": "completed",
"progress": 100
}
rate-limited:
server: my-api
description: Simulate rate limiting
match:
method: GET
path: /api/limited
respond:
- status: 200
body: |
{
"message": "Request 1 OK"
}
count: 3
- status: 429
body: |
{
"error": "Too Many Requests",
"retryAfter": 60
}
Test the sequence:
# First 2 calls return "pending"
curl http://localhost:8080/api/job/status
curl http://localhost:8080/api/job/status
# Next 3 calls return "processing"
curl http://localhost:8080/api/job/status
curl http://localhost:8080/api/job/status
curl http://localhost:8080/api/job/status
# All subsequent calls return "completed"
curl http://localhost:8080/api/job/status
Step 5: Multiple Mock Servers
Run multiple mock servers simultaneously:
mockServer:
user-service:
description: User management service
listen: ":8080"
defaults:
headers:
Content-Type: application/json
payment-service:
description: Payment processing service
listen: ":8081"
defaults:
headers:
Content-Type: application/json
notification-service:
description: Notification service
listen: ":8082"
defaults:
headers:
Content-Type: application/json
mocks:
get-user:
server: user-service
match:
method: GET
path: /users/{id}
respond:
- body: |
{
"id": "{id}",
"name": "User {id}"
}
process-payment:
server: payment-service
match:
method: POST
path: /payments
respond:
- status: 201
body: |
{
"paymentId": "pay-12345",
"status": "success"
}
send-notification:
server: notification-service
match:
method: POST
path: /notifications
respond:
- status: 202
body: |
{
"notificationId": "notif-67890",
"status": "queued"
}
Start all servers:
quadrastack --mock-server user-service --mock-server payment-service --mock-server notification-service
Test each service:
# User service on port 8080
curl http://localhost:8080/users/123
# Payment service on port 8081
curl -X POST http://localhost:8081/payments
# Notification service on port 8082
curl -X POST http://localhost:8082/notifications
Step 6: Using Base Paths
Organize your API with base paths:
mockServer:
versioned-api:
description: API with version prefix
listen: ":8080"
basePath: /api/v1
mocks:
v1-users:
server: versioned-api
description: Version 1 users endpoint
match:
method: GET
path: /users
respond:
- body: |
{
"version": "v1",
"users": []
}
Access with base path:
# basePath is automatically prepended
curl http://localhost:8080/api/v1/users
Step 7: Testing Your Mocks
Create requests.yaml to test your mock server:
requests:
test-list-users:
method: GET
url: http://localhost:8080/api/users
expect:
status: 200
body:
$: type array
$.length: "> 0"
$[0].id: exists
test-create-user:
method: POST
url: http://localhost:8080/api/users
headers:
Content-Type: application/json
body:
name: "Test User"
email: "test@example.com"
expect:
status: 201
body:
$.id: exists
$.createdAt: exists
test-auth-protected:
method: GET
url: http://localhost:8080/api/protected
headers:
Authorization: "Bearer secret-token"
expect:
status: 200
body:
$.message: "Access granted"
test-auth-denied:
method: GET
url: http://localhost:8080/api/protected
expect:
status: 401
In one terminal, start the mock server:
quadrastack --mock-server my-api
In another terminal, run the tests:
quadrastack
Step 8: Error Simulation
Create realistic error scenarios:
mocks:
server-error:
server: my-api
description: Simulate 500 error
match:
method: GET
path: /api/error/500
respond:
- status: 500
body: |
{
"error": "Internal Server Error",
"timestamp": "2024-01-01T00:00:00Z"
}
not-found:
server: my-api
description: Simulate 404 error
match:
method: GET
path: /api/users/999
respond:
- status: 404
body: |
{
"error": "User not found",
"userId": "999"
}
timeout-simulation:
server: my-api
description: Slow response
match:
method: GET
path: /api/slow
respond:
- status: 200
body: |
{
"message": "Slow response"
}
delay: "5s"
Final Project Structure
mock-server-tutorial/
├── mocks.yaml
└── requests.yaml
Your mocks.yaml should now contain all the mock definitions created in the previous steps.
What You Learned
- Creating mock servers with
mockServer - Defining mock endpoints with
mocks - HTTP method matching (GET, POST, PUT, DELETE)
- Path parameters with
{paramName} - Advanced matching (headers, query, body)
- Response sequences with
count - Running multiple mock servers
- Using base paths
- Dynamic responses
- Error simulation
Best Practices
- Use Descriptive Names - Clear mock names help with debugging
- Add Descriptions - Document what each mock does
- Set Defaults - Use server defaults for common headers
- Match Order Matters - More specific matches should come first
- Test Your Mocks - Write tests against your mock endpoints
- Simulate Reality - Include realistic errors and edge cases
- Use Sequences - Model changing state over time
- Organize by Service - Use multiple servers for microservices
Next Steps
- Authentication Workflow - Use mocks in auth flows
- Mocks Guide - Complete mock server reference
- Load Testing - Test mock servers under load
- Workflows Guide - Combine mocks with workflows
Common Issues
Port Already in Use
If port 8080 is busy, choose a different port:
mockServer:
my-api:
listen: ":8888" # Use different port
Mock Not Matching
Use verbose mode to see why requests don't match:
quadrastack --mock-server my-api --verbose
Response Not Updating
Remember sequences reset when the server restarts. Each count is per server instance.
Advanced Tips
- JSON Formatting - Use
|for multiline JSON bodies - Path Parameters - Use
{param}and reference with{param}in response - Exact vs Flexible - Use exact matches for critical fields, flexible for others
- Development Workflow - Keep mock server running, edit YAML, test immediately
- Share Mocks - Commit mocks to git for team collaboration
Congratulations! You can now build sophisticated mock API servers for testing and development.