QuadrastackQuadrastack
Documentation

Docs

Mocks

Create mock HTTP servers and define mock routes for testing without real backends

Mocks

Create mock HTTP servers to test your application without depending on real backend services.

Overview

Mocks let you simulate API responses for testing. Define mock servers and routes with custom responses, delays, and sequences. Perfect for local development, CI/CD, and testing edge cases.

Basic Mock Setup

mockServer:
  api-mock:
    listen: ":8080"

mocks:
  get-user:
    server: api-mock
    match:
      method: GET
      path: /users/{id}
    respond:
      - status: 200
        body: '{"id": "123", "name": "John Doe"}'

Mock Servers

Define mock HTTP servers with mockServer.

Basic Server

mockServer:
  api-mock:
    listen: ":8080"

Server Configuration Fields

listen (required)

Listen address and port for the mock server.

Type: string

mockServer:
  local-mock:
    listen: ":8080"           # Listen on all interfaces, port 8080

  localhost-mock:
    listen: "localhost:9000"  # Listen on localhost only, port 9000

  specific-ip:
    listen: "0.0.0.0:3000"    # Explicit IP address

basePath

Base path prefix for all routes on this server.

Type: string

mockServer:
  api-mock:
    listen: ":8080"
    basePath: /api          # All routes prefixed with /api

mocks:
  get-users:
    server: api-mock
    match:
      method: GET
      path: /users          # Full path: /api/users
    respond:
      - status: 200

tls

TLS/HTTPS configuration.

Type: object

mockServer:
  https-mock:
    listen: ":8443"
    tls:
      enabled: true
      certFile: ./certs/localhost.crt
      keyFile: ./certs/localhost.key

TLS fields:

  • enabled (boolean, required): Enable HTTPS
  • certFile (string): Path to TLS certificate
  • keyFile (string): Path to TLS private key

defaults

Default response values for all routes on this server.

Type: object

mockServer:
  api-mock:
    listen: ":8080"
    defaults:
      status: 200
      headers:
        Content-Type: application/json
        X-Mock-Server: quadrastack

Default fields:

  • status (integer): Default HTTP status code
  • headers (object): Default response headers
  • body (string): Default response body

Mock Routes

Define mock routes with mocks.

Basic Route

mocks:
  get-user:
    server: api-mock
    match:
      method: GET
      path: /users/{id}
    respond:
      - status: 200
        body: '{"id": "123", "name": "John Doe"}'

Route Fields

server (required)

Name of the mock server this route belongs to.

Type: string

mocks:
  get-user:
    server: api-mock  # References mockServer.api-mock

match (required)

Request matching rules.

Type: object

See Match Configuration below.

respond

Response sequence (same as sequence - use either one).

Type: array

mocks:
  get-user:
    server: api-mock
    match:
      method: GET
      path: /users/{id}
    respond:
      - status: 200
        body: '{"id": "123", "name": "John Doe"}'

sequence

Response sequence (same as respond - use either one). Responses are returned in order based on count.

Type: array

Note: Multiple responses in a sequence require Pro or Business license.

mocks:
  flaky-endpoint:
    server: api-mock
    match:
      method: POST
      path: /orders
    sequence:
      - count: 2
        status: 500
        body: '{"error": "Internal server error"}'
      - status: 201
        body: '{"id": "order-123", "status": "created"}'

Match Configuration

Define how requests match routes.

Note: Advanced matching (query, headers, body, form, files) requires Pro or Business license. Free tier supports method and path matching only.

method (required)

HTTP method(s) to match.

Type: string or array of strings

mocks:
  # Single method
  get-user:
    match:
      method: GET
      path: /users/{id}

  # Multiple methods
  user-endpoint:
    match:
      method: [GET, POST, PUT]
      path: /users

path (required)

Path pattern to match. Use {paramName} for path parameters.

Type: string

mocks:
  # Exact path
  get-users:
    match:
      method: GET
      path: /users

  # Path parameter
  get-user:
    match:
      method: GET
      path: /users/{id}

  # Multiple parameters
  get-comment:
    match:
      method: GET
      path: /posts/{postId}/comments/{commentId}

query

Query parameter assertions using assertion operators.

Type: object

mocks:
  search-users:
    match:
      method: GET
      path: /users
      query:
        page: exists
        limit: "> 0"
        filter: contains active

headers

Header assertions using assertion operators.

Type: object

mocks:
  authenticated-endpoint:
    match:
      method: GET
      path: /api/protected
      headers:
        Authorization: exists
        Content-Type: contains application/json

body

JSONPath body assertions using assertion operators.

Type: object

mocks:
  create-user:
    match:
      method: POST
      path: /users
      body:
        $.name: "!empty"
        $.email: 'matches ^[\w.]+@[\w.]+$'
        $.age: ">= 18"

form

Form field assertions using assertion operators.

Type: object

mocks:
  login:
    match:
      method: POST
      path: /auth/login
      form:
        username: "!empty"
        password: "length >= 8"

files

File field assertions using assertion operators.

Type: object

mocks:
  upload:
    match:
      method: POST
      path: /upload
      files:
        avatar: exists
        document: "!empty"

Response Configuration

Define mock responses with status, headers, body, and delay.

status

HTTP status code for this response.

Type: integer

respond:
  - status: 200
  - status: 404
  - status: 500

headers

Response headers.

Type: object

respond:
  - status: 200
    headers:
      Content-Type: application/json
      X-Request-ID: "123"
      Cache-Control: "max-age=3600"

body

Response body (JSON, XML, plain text, etc.).

Type: string

respond:
  # JSON
  - status: 200
    body: '{"id": "123", "name": "John Doe"}'

  # XML
  - status: 200
    body: '<user><id>123</id><name>John Doe</name></user>'

  # Plain text
  - status: 200
    body: 'OK'

Multi-line body:

respond:
  - status: 200
    body: |
      {
        "id": "123",
        "name": "John Doe",
        "email": "john@example.com",
        "active": true
      }

delay

Artificial delay before sending response.

Type: string (duration format)

Note: Response delays require Pro or Business license.

respond:
  - status: 200
    delay: "100ms"  # Wait 100ms before responding

  - status: 200
    delay: "1s"     # Wait 1 second

  - status: 200
    delay: "500ms"  # Wait 500ms

count

Number of times to return this response before moving to the next in sequence.

Type: integer Default: 0 (infinite)

sequence:
  # Return 500 twice
  - count: 2
    status: 500
    body: '{"error": "Service unavailable"}'

  # Then return 200 forever
  - status: 200
    body: '{"status": "ok"}'

Complete Examples

Simple REST API Mock

mockServer:
  api-mock:
    listen: ":8080"
    basePath: /api
    defaults:
      status: 200
      headers:
        Content-Type: application/json

mocks:
  # GET /api/users
  get-users:
    server: api-mock
    match:
      method: GET
      path: /users
    respond:
      - status: 200
        body: |
          [
            {"id": "1", "name": "Alice"},
            {"id": "2", "name": "Bob"}
          ]

  # GET /api/users/{id}
  get-user:
    server: api-mock
    match:
      method: GET
      path: /users/{id}
    respond:
      - status: 200
        body: '{"id": "123", "name": "John Doe", "email": "john@example.com"}'

  # POST /api/users
  create-user:
    server: api-mock
    match:
      method: POST
      path: /users
      body:
        $.name: exists
        $.email: exists
    respond:
      - status: 201
        headers:
          Location: /api/users/123
        body: |
          {
            "id": "123",
            "name": "New User",
            "email": "new@example.com",
            "createdAt": "2024-01-01T00:00:00Z"
          }

  # PUT /api/users/{id}
  update-user:
    server: api-mock
    match:
      method: PUT
      path: /users/{id}
    respond:
      - status: 200
        body: '{"id": "123", "name": "Updated User"}'

  # DELETE /api/users/{id}
  delete-user:
    server: api-mock
    match:
      method: DELETE
      path: /users/{id}
    respond:
      - status: 204

Flaky Service Simulation

mockServer:
  flaky-api:
    listen: ":8080"

mocks:
  # Fail twice, then succeed
  flaky-endpoint:
    server: flaky-api
    match:
      method: POST
      path: /process
    sequence:
      - count: 2
        status: 503
        delay: "100ms"
        body: '{"error": "Service temporarily unavailable"}'
      - status: 200
        body: '{"status": "success", "result": "processed"}'

  # Slow then fast
  slow-endpoint:
    server: flaky-api
    match:
      method: GET
      path: /data
    sequence:
      - count: 1
        status: 200
        delay: "5s"
        body: '{"slow": true}'
      - status: 200
        delay: "100ms"
        body: '{"fast": true}'

Authentication Mock

mockServer:
  auth-mock:
    listen: ":9000"

mocks:
  # Login - success
  login-success:
    server: auth-mock
    match:
      method: POST
      path: /auth/login
      body:
        $.username: admin
        $.password: exists
    respond:
      - status: 200
        body: |
          {
            "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
            "userId": "123",
            "expiresIn": 3600
          }

  # Login - invalid credentials
  login-failure:
    server: auth-mock
    match:
      method: POST
      path: /auth/login
      body:
        $.username: "!in [admin]"
    respond:
      - status: 401
        body: '{"error": "Invalid credentials"}'

  # Protected endpoint
  protected-resource:
    server: auth-mock
    match:
      method: GET
      path: /api/protected
      headers:
        Authorization: exists
    respond:
      - status: 200
        body: '{"data": "secret information"}'

  # No auth
  unauthorized:
    server: auth-mock
    match:
      method: GET
      path: /api/protected
      headers:
        Authorization: "!exists"
    respond:
      - status: 401
        body: '{"error": "Unauthorized"}'

Rate Limiting Mock

mockServer:
  rate-limited-api:
    listen: ":8080"

mocks:
  # First 5 requests succeed
  rate-limit-ok:
    server: rate-limited-api
    match:
      method: GET
      path: /api/data
    sequence:
      - count: 5
        status: 200
        body: '{"data": "success"}'
      - count: 3
        status: 429
        headers:
          Retry-After: "60"
        body: '{"error": "Rate limit exceeded"}'
      - status: 200
        body: '{"data": "success again"}'

Multi-Server Setup

mockServer:
  # Main API server
  api-mock:
    listen: ":8080"
    basePath: /api
    defaults:
      headers:
        Content-Type: application/json

  # Auth server
  auth-mock:
    listen: ":9000"
    defaults:
      headers:
        Content-Type: application/json

  # HTTPS mock
  secure-mock:
    listen: ":8443"
    tls:
      enabled: true
      certFile: ./certs/localhost.crt
      keyFile: ./certs/localhost.key

mocks:
  # API route
  get-users:
    server: api-mock
    match:
      method: GET
      path: /users
    respond:
      - status: 200
        body: '[{"id": "1", "name": "Alice"}]'

  # Auth route
  login:
    server: auth-mock
    match:
      method: POST
      path: /login
    respond:
      - status: 200
        body: '{"token": "abc123"}'

  # Secure route
  secure-data:
    server: secure-mock
    match:
      method: GET
      path: /secure/data
    respond:
      - status: 200
        body: '{"secure": true}'

Using Mocks with Requests

Configure requests to use mock servers:

# Start mock server
mockServer:
  api-mock:
    listen: ":8080"

# Define mock routes
mocks:
  get-users:
    server: api-mock
    match:
      method: GET
      path: /users
    respond:
      - status: 200
        body: '[{"id": "1", "name": "Alice"}]'

# Configure HTTP client to use mock
httpClients:
  default:
    baseUrl: http://localhost:8080

# Make requests against mock
requests:
  test-get-users:
    method: GET
    url: /users
    expect:
      status: 200
      body:
        $: type array
        $.length: "> 0"

Running Mock Servers

Start Mock Server

# Start mock server(s) by name
quadrastack --mock-server api-mock

# Start multiple mock servers
quadrastack --mock-server api-mock --mock-server auth-mock

Mock Server Lifecycle

Mock servers run standalone with the --mock-server flag. When using this flag, the CLI starts the mock server(s) and waits for Ctrl+C to stop them. Tests are not executed when --mock-server is specified.


Best Practices

1. Use Realistic Response Bodies

respond:
  - status: 200
    body: |
      {
        "id": "123",
        "name": "John Doe",
        "email": "john@example.com",
        "createdAt": "2024-01-01T00:00:00Z",
        "updatedAt": "2024-01-01T00:00:00Z",
        "active": true
      }

2. Match on Important Fields Only

# Good - match on required fields
match:
  method: POST
  path: /users
  body:
    $.email: exists
    $.name: exists

# Avoid - too specific, brittle
match:
  method: POST
  path: /users
  body:
    $.email: "exact@email.com"
    $.name: "Exact Name"
    $.age: 25
    $.address: exists

3. Use Sequences for Complex Scenarios

sequence:
  - count: 2
    status: 500
    body: '{"error": "Server error"}'
  - status: 200
    body: '{"status": "recovered"}'

4. Set Default Headers

mockServer:
  api-mock:
    listen: ":8080"
    defaults:
      status: 200
      headers:
        Content-Type: application/json
        X-Mock-Server: quadrastack

5. Use basePath for API Versioning

mockServer:
  api-v1:
    listen: ":8080"
    basePath: /api/v1

  api-v2:
    listen: ":8080"
    basePath: /api/v2

6. Separate Servers by Concern

mockServer:
  auth-mock:
    listen: ":9000"  # Authentication

  api-mock:
    listen: ":8080"  # Main API

  external-mock:
    listen: ":7000"  # Third-party API

7. Test Both Success and Failure

mocks:
  # Success case
  create-success:
    server: api-mock
    match:
      method: POST
      path: /users
      body:
        $.email: 'matches ^[\w.]+@[\w.]+$'
    respond:
      - status: 201

  # Failure case
  create-failure:
    server: api-mock
    match:
      method: POST
      path: /users
      body:
        $.email: "!matches ^[\\w.]+@[\\w.]+$"
    respond:
      - status: 400
        body: '{"error": "Invalid email"}'

Assertion Operators

Use these operators in match sections:

  • exists - Field must exist
  • !exists - Field must not exist
  • !empty - Field must not be empty
  • contains text - String contains text
  • !contains text - String does not contain text
  • matches regex - String matches regex
  • > N - Number greater than
  • >= N - Number greater or equal
  • < N - Number less than
  • <= N - Number less or equal
  • type <type> - Type check (string, number, array, object)
  • in [val1, val2] - Value in list
  • !in [val1, val2] - Value not in list
  • length N - Length equals N
  • length > N - Length greater than N

See Assertions for complete reference.


See Also

Mocks - Quadrastack Docs