Warning
How did you even end up here in the first place? Anyway, this software is definitely not production-ready. Do not use it-at all-unless you want to make my cat very, very sad. And trust me, you don't want that. πΎ
This project implements a simple proxy server in Rust that forwards incoming HTTP requests to a specified target URL. It supports optional CORS headers, additional extra headers in the response, and logs every incoming request.
- Request Proxying: Forwards any incoming request to the provided target URL.
- CORS Headers: Optionally adds default CORS headers (such as
Content-Type,Access-Control-Allow-Origin, etc.) to responses. - Extra Headers: Allows you to add additional custom response headers.
- Logging: Logs each incoming request (method, path, headers, etc.) using the
logcrate. - Mocking Support (New!)
- Mock Files: You may provide a TOML file specifying an array of mock configurations (
[[mocks]]). - Loading Body from File: If the
bodyparameter in the mock ends with.json,.txt, or.html, the system attempts to load that file's contents from disk. Otherwise, it uses the literal string as the body.
- Mock Files: You may provide a TOML file specifying an array of mock configurations (
- Rust (Rust 1.40 or later is recommended, which comes with Cargo)
- Internet connectivity to fetch dependencies via Cargo.
To compile the project in debug mode, run:
cargo buildFor a release build (optimized), run:
cargo build --releaseTip: If you prefer running the project with optimizations, you can launch it as a release build:
cargo run --release -- \ -t 'https://api.example.com/api/' \ -u 'http://localhost:6969' \ \ -c \ -e 'x-proxy-bob: yes' \ -e 'x-proxy-alice: no'
Also you can install it with cargo install --path=..
The proxy server accepts several command-line options:
-
--target-urlor-tThe target URL to which incoming requests are proxied. -
--api-urlor-uThe URL where the proxy server will listen for incoming requests. -
--add-cors-headersor-cWhen present, the proxy will add default CORS headers to the response. -
--extra-headeror-eExtra header(s) to include in the response. This option can be used multiple times with the format"Header-Name: value". -
--mock-fileor-mThe path to the TOML file containing mock configurations. -
--save-request-directoryor-sYou can save incoming requests to a directory. Each request will be saved as a JSON file. -
--hide-headersor-hWhen present, request headers will not be logged. Useful for security or reducing log verbosity. -
--hide-bodyor-bWhen present, request bodies will not be logged. Useful for security, privacy, or reducing log verbosity.
You can define a local TOML file (e.g., mocks.toml) with an array of [[mocks]] entries. Here's an example:
[[mocks]]
method = "GET"
path = "/test"
body = "Hello from test!"
[[mocks]]
method = "GET"
path = "/json-endpoint"
body = "data.json"
[mocks.headers]
Content-Type = "application/json"
[[mocks]]
method = "GET"
path = "/html-page"
body = "index.html"
[mocks.headers]
Content-Type = "text/html"Here's how the body field works:
- If the
bodystring ends with.json,.txt, or.html, the proxy attempts to read the file (e.g.,data.json,index.html) from disk. - If that file exists and is readable, its contents are returned as the mocked response body.
- If the file is missing, unreadable, or the extension does not match, the literal
bodystring (e.g.,"Hello from test!") is served as-is.
In other words, your mocks can either embed a raw text response or point to a file for dynamic loading.
Example usage with a mock file:
cargo run -- \
--target-url "https://api.example.com" \
--api-url "http://localhost:3000" \
--mocks "mocks.toml"or the short hand version:
cargo run -- \
-t "https://api.example.com" \
-u "http://localhost:3000" \
-m "~/demos/mocks/mocks.toml"Make sure mocks.toml is in your working directory. Then, if you hit GET /test on http://localhost:3000, you'll see "Hello from test!" (literal string), while hitting GET /json-endpoint tries to serve the contents of data.json.
Note: Always verify your paths (relative vs. absolute) based on where you execute the binary. If you wish to keep the mock files separate, include the proper path in the body field (e.g. "mocks/data.json") and ensure you run the binary from the project's root or otherwise adjust paths accordingly.
The --save-request-directory (or -s) flag allows you to save all requests and responses to a specified directory. This is useful for:
- Creating a record of API interactions
- Generating mock configurations automatically
- Debugging API responses
- Creating test fixtures
proxxyy -t "https://api.example.com" -u "http://localhost:6969" -s "./saved_requests"When you use the save feature, the following files are created in the specified directory:
-
Timestamped JSON Response Files
- Each response is saved as a beautified JSON file
- Filenames include the endpoint path, query parameters, and a timestamp
- Example:
users_page_1_per_page_10_1700000000.json - Special characters are replaced with underscores for valid filenames
-
Mock Configuration File (mocked-request.toml)
- A single TOML file containing entries for all captured requests
- Each entry includes the HTTP method, complete path with query parameters, and a reference to the JSON file
- New requests are appended to this file, preserving the history of all requests
saved_requests/
βββ mocked-request.toml
βββ users_1700000000.json
βββ users_id_123_1700000010.json
βββ users_page_1_per_page_10_1700000020.json# Mock configuration file generated by proxxyy
# Each entry represents a mock endpoint
[[mocks]]
method = "GET"
path = "/users"
status = 200
body = "users_1700000000.json"
[[mocks]]
method = "GET"
path = "/users/123"
status = 200
body = "users_id_123_1700000010.json"
[[mocks]]
method = "GET"
path = "/users?page=1&per_page=10"
status = 200
body = "users_page_1_per_page_10_1700000020.json"You can use the generated TOML file directly with the --mock-config flag to replay the saved responses:
proxxyy -t 'https://api.example.com/api/' \
-u "http://localhost:6969" \
-m "./saved_requests/mocked-request.toml"This will serve the saved responses for matching requests, without forwarding to any target URL.
The project uses the env_logger crate for logging. You can adjust the verbosity by setting the RUST_LOG environment variable before running the project. For example, to run the proxy with informational logging:
RUST_LOG=info cargo run -- \
--target-url='https://api.example.com/api/' \
--api-url='http://localhost:6969' \
--add-cors-headers \
--extra-header='x-proxy-bob: yes' \
--extra-header='x-proxy-alice: no' \
--mock-file='mocks.toml'To run the proxy server with the full parameter names:
proxxyy --add-cors-headers \
--target-url='https://api.example.com/api/' \
--api-url='http://localhost:6969' \
--extra-header='x-proxy-bob: yes' \
--extra-header='x-proxy-alice: no' \
--save-request-directory='./requests' \
--hide-headers \
--hide-bodyUsing the shorthand options:
proxxyy -c \
-t 'https://api.example.com/api/' \
-u 'http://localhost:6969' \
-e 'x-proxy-bob: yes' \
-e 'x-proxy-alice: no' \
-m 'mocks.toml' \
-s './requests' \
-h \
-b