mockbox 0.5.0

A Rust-based HTTP mock server with scripting capabilities using Rune.
mockbox-0.5.0 is not a library.

Mockbox

A flexible HTTP proxy server powered by Rune scripting. Every incoming request is first handled by a Rune script, which can either respond directly or indicate that the request should be proxied to an upstream server.

Features

  • Rune Scripting: Handle HTTP requests with dynamic Rune scripts
  • Upstream Proxy: Automatically proxy unhandled requests to another web server
  • Hot-reloadable: Modify scripts without restarting
  • Full HTTP Support: Access method, path, headers, and body in scripts

Installation

  1. Clone the repository
  2. Build the project:
cargo install mockbox

Usage

Basic Setup

  1. Run the server:
mockbox mock script.rn

  1. The server will start on http://0.0.0.0:333

Configuration

Configure the upstream server using the MOCKBOX_UPSTREAM environment variable:

MOCKBOX_UPSTREAM=http://localhost:8080 mockbox mock script.rn

or by using the appropriate cli option:

mockbox mock script.rn --upstream http://localhost:8080

Rune Script API

Your script.rn must export a handle_request function that receives a request object and returns either a response object or the string "UNHANDLED".

Request Object

The request object passed to your handler contains:

  • method: HTTP method (e.g., "GET", "POST")
  • path: Request path (e.g., "/api/users")
  • body: Request body as a string

Response Options

1. Handle the request

Return an object with status and body fields:

pub fn handle_request(request) {
    #{
        status: 200,
        body: "Hello, World!"
    }
}

2. Return a simple string

Return just a string for a 200 OK response:

pub fn handle_request(request) {
    "Hello, World!"
}

3. Proxy to upstream server

Return the string "UNHANDLED" to proxy the request:

pub fn handle_request(request) {
    "UNHANDLED"
}

Example Scripts

Mock API Endpoints

pub fn handle_request(request) {
    let path = request.path;
    let method = request.method;

    // Mock user API
    match path {
        "/api/users" if method == "GET" => {
            #{
                status: 200,
                body: json::to_string([#{ "id": 1, "name": "John" }, #{ "id": 2, "name": "Jane" }])?,
            }
        }

        // Mock authentication
        "/api/login" if method == "POST" => {
            #{ status: 200, body: json::to_string(#{ "token": "mock-jwt-token-12345" })? }
        }

        // Proxy everything else
        _ => "UNHANDLED",

    }
}

Route-based Handling

pub fn handle_request(request) {
    let path = request.path;

    match path {
        // Echo endpoint
        "/echo" => #{ status: 200, body: request.body },

        // Handle all /mock/* routes
        _ if path.starts_with("/mock/") => #{ status: 200, body: `{"mocked": true, "path": "${path}"}` },

        // Default: proxy to real server
        _ => "UNHANDLED",
    }
}

Conditional Mocking

pub fn handle_request(request) {
    let path = request.path;
    let body = request.body;

    // Mock only if body contains "test"
    if body.contains("test") {
        return #{ status: 200, body: json::to_string(#{ "message": "Test mode response" })? };
    }

    // Otherwise use real backend
    "UNHANDLED"
}

Error Responses

pub fn handle_request(request) {
    let path = request.path;

    // Simulate errors for testing
    match path {
        "/error/500" => #{ status: 500, body: "Internal Server Error" },
        "/error/404" => #{ status: 404, body: "Not Found" },
        _ => "UNHANDLED",
    }
}

Architecture

  1. Request Reception: Axum receives the HTTP request
  2. Rune Execution: The handle_request function in script.rn is called
  3. Response Decision:
    • If the script returns a response object or string → respond directly
    • If the script returns "UNHANDLED" → proxy to upstream server
  4. Upstream Proxy: Forward the original request to the configured upstream URL
  5. Response: Return the response from either Rune or the upstream server

Use Cases

  • Mock APIs: Create mock responses for testing frontend applications
  • Request Interception: Log, modify, or reject requests based on conditions
  • A/B Testing: Route requests to different backends based on rules
  • Development Environment: Override specific endpoints while keeping others real

Testing

Test your Rune scripts by making HTTP requests:

# Test a mocked endpoint

curl http://localhost:3000/hello


# Test the upstream proxy

curl http://localhost:3000/some/real/path