Skip to content

ragilhadi/mimic

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

28 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

🧩 Mimic - Lightweight HTTP Mock Server

Tests Docker License

Mimic is a fast, lightweight HTTP mock server built with Rust and Axum. Perfect for testing, development, and API prototyping. Define your mock responses in simple JSON files and let Mimic handle the rest.

Features

  • Blazing Fast - Built with Rust and Axum for maximum performance
  • Ultra Lightweight - Only 1.66 MiB memory usage
  • File-Based Configuration - Define mocks in simple JSON files
  • Hot Reload - Changes to mock files are reflected immediately
  • Docker Ready - Pre-built images available on Docker Hub
  • Well Tested - 60+ unit tests with high code coverage
  • Easy to Use - Simple configuration, no complex setup
  • Configurable Body Consumption - Control request body handling per endpoint
  • File Upload Support - Handle multipart/form-data with consume_body option
  • Advanced Matching - Match on query params, headers, and request body

Performance

Mimic is incredibly efficient and lightweight:

CONTAINER ID   NAME      CPU %     MEM USAGE / LIMIT    MEM %     NET I/O           BLOCK I/O   PIDS
b056ebec5099   mimic     0.02%     1.66MiB / 6.238GiB   0.03%     17.1kB / 34.6kB   0B / 0B     17

Key Metrics:

  • Memory Usage: Only 1.66 MiB (yes, megabytes!)
  • CPU Usage: 0.02% at idle
  • Startup Time: < 1 second
  • Response Time: < 10ms for most requests

Perfect for resource-constrained environments, CI/CD pipelines, and local development.


πŸš€ Quick Start

Using Docker (Recommended)

Pull the latest image from Docker Hub:

docker pull ragilhadi/mimic:latest

Run with your mock files:

docker run -d \
  --name mimic \
  -p 8080:8080 \
  -v $(pwd)/mocks:/app/mocks:ro \
  ragilhadi/mimic:latest

Test it:

curl http://localhost:8080/health

Using Docker Compose

  1. Create a docker-compose.yml:
services:
  mimic:
    image: ragilhadi/mimic:latest
    container_name: mimic
    ports:
      - "8080:8080"
    volumes:
      - ./mocks:/app/mocks:ro
    environment:
      - PORT=8080
      - RUST_LOG=info
    restart: unless-stopped
  1. Start the service:
docker compose up -d

πŸ“ Configuration

Environment Variables

Create a .env file to customize your setup:

# Port configuration (default: 8080)
PORT=8080

# Logging level: trace, debug, info, warn, error (default: info)
RUST_LOG=info

Log Levels:

  • trace - Very detailed debugging
  • debug - Detailed debugging
  • info - General information (recommended)
  • warn - Warnings only
  • error - Errors only

Mock Files

Mimic reads mock definitions from JSON files in the /app/mocks directory (or ./mocks locally).

Mock File Structure:

{
  "method": "GET",
  "path": "/users",
  "status": 200,
  "response": {
    "users": [
      {
        "id": 1,
        "name": "Alice Johnson",
        "email": "alice@example.com"
      }
    ]
  }
}

Fields:

  • method - HTTP method (GET, POST, PUT, DELETE, PATCH, etc.)
  • path - URL path (e.g., /users, /api/v1/products)
  • status - HTTP status code (200, 201, 404, 500, etc.)
  • response - JSON response body (can be object, array, or null)
  • consume_body - (Optional) Boolean to control request body consumption (default: false)
    • true - Consume request body (required for file uploads, multipart/form-data)
    • false - Skip body consumption (faster, default behavior)

πŸ“ Mock Examples

Example 1: GET Request

File: mocks/get_users.json

{
  "method": "GET",
  "path": "/users",
  "status": 200,
  "response": {
    "users": [
      {
        "id": 1,
        "name": "Alice Johnson",
        "email": "alice@example.com",
        "role": "admin"
      },
      {
        "id": 2,
        "name": "Bob Smith",
        "email": "bob@example.com",
        "role": "user"
      }
    ],
    "total": 2
  }
}

Usage:

curl http://localhost:8080/users

Example 2: POST Request

File: mocks/post_login.json

{
  "method": "POST",
  "path": "/login",
  "status": 200,
  "response": {
    "success": true,
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "user": {
      "id": 1,
      "username": "admin",
      "email": "admin@example.com"
    },
    "expiresIn": 3600
  }
}

Usage:

curl -X POST http://localhost:8080/login

Example 3: Error Response

File: mocks/get_error.json

{
  "method": "GET",
  "path": "/error",
  "status": 500,
  "response": {
    "error": "Internal Server Error",
    "message": "Something went wrong",
    "code": "ERR_500"
  }
}

Usage:

curl http://localhost:8080/error

Example 4: DELETE Request

File: mocks/delete_user.json

{
  "method": "DELETE",
  "path": "/users/123",
  "status": 204,
  "response": null
}

Usage:

curl -X DELETE http://localhost:8080/users/123

Example 5: File Upload with consume_body

File: mocks/ocr_image.json

{
  "method": "POST",
  "path": "/ocr-image",
  "status": 200,
  "consume_body": true,
  "response": {
    "status": "SUCCESS",
    "text": "Extracted text from image",
    "confidence": 0.95,
    "detected_text": [
      {
        "text": "Hello World",
        "bbox": [10, 20, 100, 40]
      }
    ]
  }
}

Usage:

# Upload image file
curl -X POST http://localhost:8080/ocr-image \
  -F "image=@document.jpg" \
  -F "language=en"

Note: Set consume_body: true for endpoints that handle:

  • File uploads (images, documents, etc.)
  • Multipart/form-data requests
  • Large request payloads

Without consume_body: true, clients may encounter "Broken Pipe" errors when sending large files.


🎯 Advanced Matching

Mimic supports advanced request matching beyond just HTTP method and path. You can match requests based on query parameters, headers, and request body content.

Query Parameter Matching

Match requests based on URL query string parameters:

File: mocks/get_search.json

{
  "method": "GET",
  "path": "/search",
  "status": 200,
  "query_params": {
    "params": {
      "q": "test",
      "page": "1"
    },
    "strict": false
  },
  "response": {
    "results": [
      {"id": 1, "title": "Test Result 1"},
      {"id": 2, "title": "Test Result 2"}
    ],
    "query": "test",
    "page": 1
  }
}

Usage:

# Matches - exact params
curl "http://localhost:8080/search?q=test&page=1"

# Matches - extra params ignored (strict=false)
curl "http://localhost:8080/search?q=test&page=1&extra=value"

# Doesn't match - wrong value
curl "http://localhost:8080/search?q=wrong&page=1"  # Returns 404

Advanced Query Patterns:

{
  "query_params": {
    "params": {
      "page": {"regex": "^[0-9]+$"},
      "limit": {"regex": "^(10|20|50|100)$"},
      "status": {"any": null}
    },
    "strict": false
  }
}
  • Exact match: "param": "value"
  • Regex match: "param": {"regex": "^pattern$"}
  • Any value: "param": {"any": null} (param must exist)
  • Strict mode: "strict": true (rejects extra params)

Header Matching

Match requests based on HTTP headers:

File: mocks/get_protected.json

{
  "method": "GET",
  "path": "/api/protected",
  "status": 200,
  "headers": {
    "required": {
      "authorization": {
        "prefix": "Bearer "
      }
    },
    "forbidden": [],
    "strict": false
  },
  "response": {
    "data": "This is protected content",
    "user": {
      "id": 1,
      "role": "admin"
    }
  }
}

Usage:

# Matches - valid Bearer token
curl -H "Authorization: Bearer my_token" http://localhost:8080/api/protected

# Doesn't match - missing header
curl http://localhost:8080/api/protected  # Returns 404

# Doesn't match - wrong prefix
curl -H "Authorization: Basic token" http://localhost:8080/api/protected  # Returns 404

Advanced Header Patterns:

{
  "headers": {
    "required": {
      "authorization": "Bearer token123",
      "content-type": {"contains": "json"},
      "x-api-key": {"regex": "^[A-Za-z0-9]{32}$"},
      "accept": {"any": null}
    },
    "forbidden": ["x-debug", "x-internal"],
    "strict": false
  }
}
  • Exact match: "header": "value"
  • Prefix match: "header": {"prefix": "Bearer "}
  • Contains: "header": {"contains": "substring"}
  • Regex match: "header": {"regex": "^pattern$"}
  • Any value: "header": {"any": null}
  • Forbidden headers: Headers that must NOT be present
  • Case-insensitive: Header names are case-insensitive (per HTTP spec)

Request Body Matching

Match requests based on JSON, text, or form data in the request body:

JSON Body Matching

File: mocks/post_login.json

{
  "method": "POST",
  "path": "/api/login",
  "status": 200,
  "headers": {
    "required": {
      "content-type": "application/json"
    }
  },
  "body": {
    "type": "json",
    "partial": {
      "username": "admin",
      "password": "secret123"
    }
  },
  "response": {
    "success": true,
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "user": {
      "id": 1,
      "username": "admin",
      "role": "admin"
    }
  }
}

Usage:

# Matches - exact credentials
curl -X POST http://localhost:8080/api/login \
  -H "Content-Type: application/json" \
  -d '{"username":"admin","password":"secret123"}'

# Matches - extra fields ignored (partial matching)
curl -X POST http://localhost:8080/api/login \
  -H "Content-Type: application/json" \
  -d '{"username":"admin","password":"secret123","remember_me":true}'

# Doesn't match - wrong password
curl -X POST http://localhost:8080/api/login \
  -H "Content-Type: application/json" \
  -d '{"username":"admin","password":"wrong"}'  # Returns 404

JSON Body Options:

{
  "body": {
    "type": "json",
    "exact": {"key": "value"},      // Entire body must match exactly
    "partial": {"name": "Alice"},   // Specified fields must match
    "strict": false                 // If true with partial, reject extra fields
  }
}

Text Body Matching

{
  "body": {
    "type": "text",
    "contains": "search term"
  }
}

Text Body Options:

  • Exact: "exact": "exact string"
  • Contains: "contains": "substring"
  • Regex: "regex": "^pattern$"

Form Body Matching

{
  "body": {
    "type": "form",
    "fields": {
      "username": "admin",
      "password": "secret"
    },
    "strict": false
  }
}

Combined Matching

Combine all matching types for precise mock selection:

File: mocks/post_search_combined.json

{
  "method": "POST",
  "path": "/api/search",
  "status": 200,
  "query_params": {
    "params": {
      "type": "user"
    }
  },
  "headers": {
    "required": {
      "authorization": {"prefix": "Bearer "},
      "content-type": "application/json"
    }
  },
  "body": {
    "type": "json",
    "partial": {
      "query": "Alice"
    }
  },
  "response": {
    "results": [
      {
        "id": 1,
        "name": "Alice Johnson",
        "email": "alice@example.com"
      }
    ],
    "total": 1
  }
}

Usage:

curl -X POST "http://localhost:8080/api/search?type=user" \
  -H "Authorization: Bearer my_token" \
  -H "Content-Type: application/json" \
  -d '{"query":"Alice","filters":{"active":true}}'

This mock only matches when all criteria are met:

  1. βœ… Method is POST
  2. βœ… Path is /api/search
  3. βœ… Query param type=user
  4. βœ… Authorization header starts with "Bearer "
  5. βœ… Content-Type is application/json
  6. βœ… Body contains {"query": "Alice"}

Match Priority

When multiple mocks could match a request, Mimic uses a scoring system:

  • Base score: Method + Path match (1000 points)
  • Query params: +100 points per matched param
  • Headers: +50 points per matched header
  • Body: +500 points if body matches

The mock with the highest score wins.


🎯 Use Cases

1. Frontend Development

Mock backend APIs while building your frontend:

# Start Mimic with your API mocks
docker run -d -p 8080:8080 -v ./mocks:/app/mocks:ro ragilhadi/mimic:latest

# Point your frontend to http://localhost:8080

2. API Prototyping

Quickly prototype API responses:

# Create mock files
echo '{"method":"GET","path":"/api/v1/products","status":200,"response":[]}' > mocks/products.json

# Start Mimic
docker compose up -d

3. Third-Party API Simulation

Simulate external APIs for testing:

# Mock Stripe API
# Mock GitHub API
# Mock any REST API

πŸ› οΈ Development

Prerequisites

  • Rust 1.70+ (for building from source)
  • Docker (for containerized development)
  • Make (optional, for convenience commands)

Local Development

  1. Clone the repository:
git clone https://github.com/ragilhadi/mimic.git
cd mimic
  1. Run locally:
# Using Makefile
make dev

# Or using Cargo directly
cargo run
  1. Run tests:
# Run all tests
make test

# Run with verbose output
make test-verbose

# Generate coverage report
make test-coverage

Available Make Commands

# Development
make dev          # Run development server with debug logging
make watch        # Auto-rebuild and run on file changes
make check        # Quick compile check

# Building
make build        # Build debug binary
make release      # Build optimized release binary

# Testing
make test         # Run all tests
make test-verbose # Run tests with output
make test-coverage# Generate test coverage report
make ci-local     # Run all CI checks locally

# Code Quality
make fmt          # Format code with rustfmt
make lint         # Run clippy linter
make audit        # Security audit of dependencies

# Docker
make docker-build       # Build Docker image
make docker-run         # Run in Docker container
make docker-compose-up  # Start with docker-compose
make docker-compose-down# Stop docker-compose services

# Cleanup
make clean        # Remove build artifacts

πŸ”„ CI/CD

Mimic uses GitHub Actions for automated testing and deployment:

Workflows

  1. Unit Tests (.github/workflows/unit-test.yml)

    • Runs on every push to main
    • Runs on every pull request
    • Checks code formatting
    • Runs linter (clippy)
    • Executes all 35+ unit tests
    • Tests on multiple Rust versions (stable, beta, nightly)
    • Performs security audit
    • Generates coverage report
  2. Docker Build & Push (.github/workflows/docker-build-push.yml)

    • Builds Docker image on push to main
    • Pushes to Docker Hub automatically
    • Multi-platform support (amd64, arm64)
    • Version tagging from vars/version file

Quality Metrics

  • βœ… 35+ Unit Tests - Comprehensive test coverage
  • βœ… ~90% Code Coverage - High quality assurance
  • βœ… Zero Clippy Warnings - Clean, idiomatic Rust code
  • βœ… Security Audited - Dependencies checked for vulnerabilities

πŸ“¦ Docker Hub

Pre-built images are available on Docker Hub:

Repository: ragilhadi/mimic

Available Tags

# Latest version
docker pull ragilhadi/mimic:latest

# Specific version
docker pull ragilhadi/mimic:v1.0.0

Image Details

  • Base Image: Debian Bookworm Slim
  • Size: ~90 MB (compressed)
  • Platforms: linux/amd64, linux/arm64
  • Runtime: Minimal dependencies (ca-certificates, wget)

πŸ” Health Check

Mimic includes a built-in health check endpoint:

curl http://localhost:8080/health

Response:

{
  "status": "healthy",
  "mocks_loaded": 5,
  "service": "mimic"
}

Use this endpoint for:

  • Docker health checks
  • Kubernetes liveness/readiness probes
  • Load balancer health checks
  • Monitoring systems

βš™οΈ Request Body Consumption

Mimic supports configurable request body consumption per endpoint via the consume_body field.

Default Behavior

By default, consume_body is false (fast performance):

  • Mimic responds immediately without reading the request body
  • Optimal for endpoints that don't need the body
  • Best performance and lowest memory usage

When to Use consume_body: true

Set consume_body: true for endpoints that handle:

  1. File Uploads

    {
      "method": "POST",
      "path": "/upload-document",
      "status": 200,
      "consume_body": true,
      "response": {"uploaded": true}
    }
  2. Multipart/Form-Data

    {
      "method": "POST",
      "path": "/ocr-image",
      "status": 200,
      "consume_body": true,
      "response": {"text": "extracted text"}
    }
  3. Large Payloads

    • Prevents "Broken Pipe" errors
    • Required when clients send large request bodies
    • Critical for image/document processing endpoints

Performance Comparison

consume_body Speed Memory Use Case
false (default) ⚑ Fastest Minimal No body expected
true Standard Temporary spike File uploads, large payloads

Example:

# Works with consume_body: true
curl -X POST http://localhost:8080/ocr-image \
  -F "image=@large-document.jpg"

# Works with consume_body: false (default)
curl -X POST http://localhost:8080/trigger-job

πŸ“– API Reference

Endpoints

Health Check

GET /health

Returns server status and number of loaded mocks.

Response:

{
  "status": "healthy",
  "mocks_loaded": 5,
  "service": "mimic"
}

Mock Endpoints

All other endpoints are defined by your mock files. Mimic will:

  1. Match the HTTP method and path
  2. Return the configured status code
  3. Return the configured response body

If no mock matches:

{
  "error": "mock not found",
  "method": "GET",
  "path": "/undefined"
}

🀝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Development Workflow

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Run tests: make test
  5. Run linter: make lint
  6. Format code: make fmt
  7. Submit a pull request

Running Tests

# Run all tests
make test

# Run with coverage
make test-coverage

# Run all CI checks
make ci-local

πŸ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.


πŸ™ Acknowledgments

Built with:

  • Rust - Systems programming language
  • Axum - Web framework
  • Tokio - Async runtime
  • Serde - Serialization framework

πŸ“ž Support


πŸ—ΊοΈ Roadmap

  • Request body matching
  • Query parameter matching
  • Header matching
  • Response delays
  • Admin UI
  • Hot reload for mock files

Made with ❀️ using Rust

About

Mimic is a fast, lightweight HTTP mock server built with Rust and Axum. Perfect for testing, development, and API prototyping. Define your mock responses in simple JSON files and let Mimic handle the rest.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors