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.
- 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_bodyoption - Advanced Matching - Match on query params, headers, and request body
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.
Pull the latest image from Docker Hub:
docker pull ragilhadi/mimic:latestRun with your mock files:
docker run -d \
--name mimic \
-p 8080:8080 \
-v $(pwd)/mocks:/app/mocks:ro \
ragilhadi/mimic:latestTest it:
curl http://localhost:8080/health- 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- Start the service:
docker compose up -dCreate a .env file to customize your setup:
# Port configuration (default: 8080)
PORT=8080
# Logging level: trace, debug, info, warn, error (default: info)
RUST_LOG=infoLog Levels:
trace- Very detailed debuggingdebug- Detailed debugginginfo- General information (recommended)warn- Warnings onlyerror- Errors only
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)
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/usersFile: 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/loginFile: 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/errorFile: mocks/delete_user.json
{
"method": "DELETE",
"path": "/users/123",
"status": 204,
"response": null
}Usage:
curl -X DELETE http://localhost:8080/users/123File: 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.
Mimic supports advanced request matching beyond just HTTP method and path. You can match requests based on query parameters, headers, and request body content.
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 404Advanced 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)
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 404Advanced 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)
Match requests based on JSON, text, or form data in the request body:
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 404JSON 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
}
}{
"body": {
"type": "text",
"contains": "search term"
}
}Text Body Options:
- Exact:
"exact": "exact string" - Contains:
"contains": "substring" - Regex:
"regex": "^pattern$"
{
"body": {
"type": "form",
"fields": {
"username": "admin",
"password": "secret"
},
"strict": false
}
}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:
- β Method is POST
- β
Path is
/api/search - β
Query param
type=user - β Authorization header starts with "Bearer "
- β Content-Type is application/json
- β
Body contains
{"query": "Alice"}
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.
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:8080Quickly prototype API responses:
# Create mock files
echo '{"method":"GET","path":"/api/v1/products","status":200,"response":[]}' > mocks/products.json
# Start Mimic
docker compose up -dSimulate external APIs for testing:
# Mock Stripe API
# Mock GitHub API
# Mock any REST API- Rust 1.70+ (for building from source)
- Docker (for containerized development)
- Make (optional, for convenience commands)
- Clone the repository:
git clone https://github.com/ragilhadi/mimic.git
cd mimic- Run locally:
# Using Makefile
make dev
# Or using Cargo directly
cargo run- Run tests:
# Run all tests
make test
# Run with verbose output
make test-verbose
# Generate coverage report
make test-coverage# 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 artifactsMimic uses GitHub Actions for automated testing and deployment:
-
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
- Runs on every push to
-
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/versionfile
- Builds Docker image on push to
- β 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
Pre-built images are available on Docker Hub:
Repository: ragilhadi/mimic
# Latest version
docker pull ragilhadi/mimic:latest
# Specific version
docker pull ragilhadi/mimic:v1.0.0- Base Image: Debian Bookworm Slim
- Size: ~90 MB (compressed)
- Platforms: linux/amd64, linux/arm64
- Runtime: Minimal dependencies (ca-certificates, wget)
Mimic includes a built-in health check endpoint:
curl http://localhost:8080/healthResponse:
{
"status": "healthy",
"mocks_loaded": 5,
"service": "mimic"
}Use this endpoint for:
- Docker health checks
- Kubernetes liveness/readiness probes
- Load balancer health checks
- Monitoring systems
Mimic supports configurable request body consumption per endpoint via the consume_body field.
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
Set consume_body: true for endpoints that handle:
-
File Uploads
{ "method": "POST", "path": "/upload-document", "status": 200, "consume_body": true, "response": {"uploaded": true} } -
Multipart/Form-Data
{ "method": "POST", "path": "/ocr-image", "status": 200, "consume_body": true, "response": {"text": "extracted text"} } -
Large Payloads
- Prevents "Broken Pipe" errors
- Required when clients send large request bodies
- Critical for image/document processing endpoints
| 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-jobGET /health
Returns server status and number of loaded mocks.
Response:
{
"status": "healthy",
"mocks_loaded": 5,
"service": "mimic"
}All other endpoints are defined by your mock files. Mimic will:
- Match the HTTP method and path
- Return the configured status code
- Return the configured response body
If no mock matches:
{
"error": "mock not found",
"method": "GET",
"path": "/undefined"
}Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create a feature branch
- Make your changes
- Run tests:
make test - Run linter:
make lint - Format code:
make fmt - Submit a pull request
# Run all tests
make test
# Run with coverage
make test-coverage
# Run all CI checks
make ci-localThis project is licensed under the MIT License - see the LICENSE file for details.
Built with:
- Rust - Systems programming language
- Axum - Web framework
- Tokio - Async runtime
- Serde - Serialization framework
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Docker Hub: ragilhadi/mimic
- Request body matching
- Query parameter matching
- Header matching
- Response delays
- Admin UI
- Hot reload for mock files
Made with β€οΈ using Rust