mockbox 0.5.0

A Rust-based HTTP mock server with scripting capabilities using Rune.
# 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:
```bash
cargo install mockbox

```

## Usage


### Basic Setup


1. Run the server:
```bash
mockbox mock script.rn

```

2. The server will start on `http://0.0.0.0:333`

### Configuration


Configure the upstream server using the `MOCKBOX_UPSTREAM` environment variable:

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

or by using the appropriate cli option:

```bash
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:

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

#### 2. Return a simple string


Return just a string for a 200 OK response:

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

#### 3. Proxy to upstream server


Return the string `"UNHANDLED"` to proxy the request:

```rs
pub fn handle_request(request) {
    "UNHANDLED"
}
```

## Example Scripts


### Mock API Endpoints


```rs
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


```rs
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


```rs
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


```rs
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:

```bash
# Test a mocked endpoint

curl http://localhost:3000/hello

# Test the upstream proxy

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