Skip to content

A single-binary mock API server. YAML config, fake data, stateful CRUD, proxy mode, record & replay, hot-reload. Like json-server but faster, with zero dependencies.

License

Notifications You must be signed in to change notification settings

purpleneutral/mockapi

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

mockapi
A single-binary mock API server. YAML config, fake data, stateful CRUD, proxy mode, record & replay, hot-reload.

CI Release License


json-server, but a single binary. YAML config. Custom status codes, delays, templates, fake data, conditional responses, hot-reload. No Node.js required.

mockapi is a single-binary mock API server that spins up a fake REST API from a YAML config file. No runtime, no dependencies, no build step.

Install

Download a prebuilt binary from the latest release:

# Linux (x86_64)
curl -LO https://github.com/purpleneutral/mockapi/releases/latest/download/mockapi-x86_64-unknown-linux-gnu.tar.gz
tar xzf mockapi-x86_64-unknown-linux-gnu.tar.gz
sudo mv mockapi /usr/local/bin/

# macOS (Apple Silicon)
curl -LO https://github.com/purpleneutral/mockapi/releases/latest/download/mockapi-aarch64-apple-darwin.tar.gz
tar xzf mockapi-aarch64-apple-darwin.tar.gz
sudo mv mockapi /usr/local/bin/

# macOS (Intel)
curl -LO https://github.com/purpleneutral/mockapi/releases/latest/download/mockapi-x86_64-apple-darwin.tar.gz
tar xzf mockapi-x86_64-apple-darwin.tar.gz
sudo mv mockapi /usr/local/bin/

Or build from source:

cargo install --git https://github.com/purpleneutral/mockapi.git

Quick Start

# Generate a starter config
mockapi init

# Start the server
mockapi serve

That's it. You have a mock API running on http://localhost:8080.

curl http://localhost:8080/users
curl http://localhost:8080/users/42
curl -X POST http://localhost:8080/users \
  -H "Content-Type: application/json" \
  -d '{"name":"Charlie","email":"charlie@test.com"}'

Config

Everything lives in one YAML file:

server:
  port: 8080
  cors: true

routes:
  - method: GET
    path: /users
    status: 200
    body:
      - id: 1
        name: Alice
      - id: 2
        name: Bob

  - method: GET
    path: /users/:id
    status: 200
    body:
      id: "{{ params.id }}"
      name: "{{ fake.name }}"
      email: "{{ fake.email }}"

  - method: POST
    path: /users
    status: 201
    body:
      id: "{{ fake.uuid }}"
      name: "{{ request.body.name }}"
      created_at: "{{ now }}"

  - method: GET
    path: /slow
    delay: 2000
    status: 200
    body:
      message: Finally here

Edit the file while the server is running — it hot-reloads automatically.

Features

  • Route matching — exact paths, parameters (:id), wildcards (**)
  • All HTTP methods — GET, POST, PUT, PATCH, DELETE, OPTIONS, HEAD, ANY
  • Custom status codes — per route
  • Custom headers — per route and global defaults
  • Response delays — per route and global default
  • Templates{{ params.id }}, {{ request.body.name }}, {{ query.page }}, {{ now }}, {{ seq }}
  • Fake data{{ fake.name }}, {{ fake.email }}, {{ fake.uuid }}, {{ fake.int(1, 100) }}, and more
  • Conditional responses — return different bodies/statuses based on query, headers, or body content
  • Stateful mode — in-memory CRUD with auto-ID, filtering, sorting, pagination
  • Proxy mode — forward unmatched requests to a real backend
  • Record & replay — record real API responses, replay them as mocks
  • File responsesfile: responses/data.json
  • CORS — enabled by default, configurable origins
  • Hot-reload — edit config, routes update instantly
  • Colored logging — minimal or verbose mode
  • Helpful 404s — tells you what to add to your config

CLI

mockapi serve                     # start server (default: ./mockapi.yaml)
mockapi serve -c api.yaml         # use a specific config
mockapi serve -p 3001             # custom port
mockapi serve -d 500              # add 500ms delay to all responses
mockapi serve --log verbose       # full request/response details
mockapi serve --no-cors           # disable CORS
mockapi serve --no-watch          # disable hot-reload

mockapi init                      # generate starter config
mockapi init -o api.yaml          # custom output path

mockapi validate                  # check config for errors
mockapi validate -c api.yaml     # validate a specific file

mockapi record -t https://api.example.com    # record from a real API
mockapi record -t https://api.example.com -o api.yaml  # custom output
mockapi record -t https://api.example.com --filter "/api/**"  # filter paths

Fake Data Generators

Generate realistic random data in templates:

body:
  id: "{{ fake.uuid }}"
  name: "{{ fake.name }}"
  first: "{{ fake.firstName }}"
  last: "{{ fake.lastName }}"
  email: "{{ fake.email }}"
  phone: "{{ fake.phone }}"
  company: "{{ fake.company }}"
  address: "{{ fake.address }}"
  url: "{{ fake.url }}"
  color: "{{ fake.color }}"
  active: "{{ fake.bool }}"
  score: "{{ fake.int(1, 100) }}"
  price: "{{ fake.float(9.99, 99.99, 2) }}"
  bio: "{{ fake.lorem(20) }}"
  status: "{{ fake.pick('active', 'inactive', 'pending') }}"

Every request returns different random values.

Conditional Responses

Return different responses based on request properties. First match wins; if no condition matches, the default body/status is used.

routes:
  - method: POST
    path: /auth/login
    status: 200
    body:
      token: "default-token"

    responses:
      # Admin credentials
      - when:
          body:
            email: admin@test.com
            password: admin123
        status: 200
        body:
          token: "admin-jwt-token"
          role: admin

      # Wrong password
      - when:
          body:
            password: wrong
        status: 401
        body:
          error: Invalid credentials

      # Missing fields
      - when:
          body_missing:
            - email
            - password
        status: 400
        body:
          error: Missing required fields

When Clause Options

when:
  query:                    # match query parameters
    role: admin
  headers:                  # match request headers (case-insensitive)
    Authorization: "Bearer valid-token"
  body:                     # match request body fields (partial/subset match)
    email: admin@test.com
  body_has:                 # require fields to exist in body
    - email
    - password
  body_missing:             # require fields to NOT exist in body
    - token

All conditions in a when clause are ANDed together.

Stateful Mode

Enable in-memory CRUD — POST creates, GET reads, PUT/PATCH updates, DELETE removes. No code required, just declare your resources:

stateful:
  enabled: true
  resources:
    - path: /users
      id_field: id
      seed:
        - id: 1
          name: Alice
        - id: 2
          name: Bob

    - path: /posts
      id_field: id
      seed: []

This auto-generates these endpoints:

Method Endpoint Behavior Status
GET /users List all 200
GET /users/1 Get by ID 200 / 404
POST /users Create (auto-ID) 201
PUT /users/1 Full replace 200 / 404
PATCH /users/1 Partial update 200 / 404
DELETE /users/1 Remove 204 / 404

Query parameters on list endpoints:

# Filter by field value
curl http://localhost:8080/users?name=Alice

# Sort
curl http://localhost:8080/users?_sort=name&_order=desc

# Paginate (adds X-Total-Count header)
curl http://localhost:8080/users?_page=1&_limit=10

Explicit routes always override stateful endpoints. State is in-memory only — resets on server restart.

Proxy Mode

Forward unmatched requests to a real backend. Explicit routes and stateful resources are checked first — only requests that don't match anything get proxied.

server:
  port: 8080

proxy:
  enabled: true
  target: "https://api.example.com"
  pass_headers: true    # forward request headers (default: true)

routes:
  # Override specific endpoints locally
  - method: GET
    path: /api/feature-flags
    status: 200
    body:
      dark_mode: true
      new_dashboard: true

This lets you:

  • Mock specific endpoints while proxying the rest to a real API
  • Develop against a real backend with selective overrides
  • Test edge cases by intercepting specific routes

Proxy returns 502 Bad Gateway if the upstream is unreachable. Upstream response status, headers, and body are forwarded as-is.

Record & Replay

Record responses from a real API and replay them as mocks. No config writing needed.

# Record from a real API
mockapi record -t https://jsonplaceholder.typicode.com -o recorded.yaml

# Make requests through the recorder (they're proxied to the real API)
curl http://localhost:8080/users
curl http://localhost:8080/users/1
curl http://localhost:8080/posts/1

# Press Ctrl+C — routes are saved to recorded.yaml

# Replay the recording
mockapi serve -c recorded.yaml

Options:

  • -t, --target <url> — target API URL (required)
  • -o, --output <path> — output file (default: ./recorded.yaml)
  • -p, --port <port> — local port (default: 8080)
  • --filter <pattern> — only record matching paths (e.g., "/api/**")

Each unique method+path is recorded once (first response wins). The output is a valid mockapi config file.

Template Variables

# Path parameters (from /users/:id)
"{{ params.id }}"

# Query parameters (from ?page=2)
"{{ query.page }}"

# Request body fields
"{{ request.body.name }}"
"{{ request.body.email }}"

# Request metadata
"{{ request.method }}"
"{{ request.path }}"
"{{ request.headers.authorization }}"

# Built-in
"{{ now }}"          # ISO 8601 timestamp
"{{ now_unix }}"     # Unix timestamp (seconds)
"{{ now_ms }}"       # Unix timestamp (milliseconds)
"{{ seq }}"          # Auto-incrementing counter

Examples

See the examples/ directory:

  • examples/basic.yaml — stateful CRUD with fake data and conditional responses
  • examples/ecommerce.yaml — products, cart, checkout with fake data and conditional responses
  • examples/auth.yaml — login with conditional responses, token validation
  • examples/proxy.yaml — proxy to a real API with local overrides
mockapi serve -c examples/ecommerce.yaml

Building from Source

git clone https://github.com/purpleneutral/mockapi.git
cd mockapi
cargo build --release
ls -lh target/release/mockapi   # ~5.6 MB

Support

If you find mockapi useful, consider supporting the project:

Buy Me a Coffee

License

GPL-3.0

About

A single-binary mock API server. YAML config, fake data, stateful CRUD, proxy mode, record & replay, hot-reload. Like json-server but faster, with zero dependencies.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages