Rusty Requester

A native, offline API client built with Rust and egui. One binary, no bundled browser, no account.

Documented at v0.28.4

What it is

Rusty Requester builds, sends, and inspects HTTP requests. It is a desktop application written in Rust on the egui immediate-mode toolkit, so it draws its own interface instead of shipping a browser engine to draw it. There is no account, no sign-in, and no background sync. Your workspace is one JSON file on your own disk.

The name is a double meaning. Rust the language, and rust as in older hardware that still does the job: the readme states that developers on older or low-spec machines are who this is built for first.

It is a graphical application, not a command-line tool. The binary accepts exactly one flag, --version, and everything else happens in the window. If you were looking for a scriptable HTTP client, curl is still the right answer, and this app will paste your curl commands in and hand them back as redacted snippets.

This page covers installation and the reference tables you will want at hand. The task-by-task guide, covering the request builder, environments, auth, the collection runner, imports, exports, backups, and troubleshooting, lives in the full guide.

Install

macOS and Linux, resolves the current release automatically
curl -fsSL https://raw.githubusercontent.com/chud-lori/rusty-requester/main/install.sh | bash

The installer asks latest.json on this site which release is current, and falls back to the GitHub Releases API if that file cannot be reached. Pin a version with VERSION= instead.

What the installer does

macOS
Downloads RustyRequester-vX.Y.Z-macos-universal.dmg, mounts it, copies RustyRequester.app into /Applications (or ~/Applications when the system folder is not writable), quits a running instance, removes the Gatekeeper quarantine attribute, re-registers the bundle with Launch Services, and prints the installed binary's SHA-256.
Linux
Downloads RustyRequester-vX.Y.Z-linux-x86_64.tar.gz, extracts it, and runs the bundled install-local.sh, which puts the binary in ~/.local/bin and registers a .desktop entry. No sudo. If ~/.local/bin is not on your PATH, the script says so and prints the line to add.

Installer environment variables

Read from install.sh. Prefix them before bash, for example | VERSION=v0.28.0 bash.
VariableEffect
VERSIONInstall a specific release tag instead of the current one.
UNINSTALL=1Remove the installed app. Keeps your data.
PURGE=1With UNINSTALL=1, also delete the data directory.
SKIP_QUARANTINE_STRIP=1macOS only. Leave Gatekeeper's quarantine attribute in place, so you confirm the first launch yourself.
RUSTY_REPOPull release assets from another owner/name repository.
RUSTY_LATEST_JSON_URLPoint version resolution at a different metadata URL.

Uninstall

Removes the app, keeps your workspace
curl -fsSL https://raw.githubusercontent.com/chud-lori/rusty-requester/main/install.sh | UNINSTALL=1 bash

Add PURGE=1 to delete the data directory as well.

Build from source

Requires Rust 1.73 or newer
git clone https://github.com/chud-lori/rusty-requester cd rusty-requester make release

make run builds and runs a debug build, make app builds a macOS bundle, make app-install builds it and copies it to /Applications, and make help lists every target. Plain Cargo works too.

First launch on macOS

The app is not notarised by Apple, so a manually installed copy triggers the "cannot be opened because Apple cannot check it" dialog once. Right-click the app and choose Open, or approve it under System Settings, Privacy and Security. The one-line installer removes the quarantine attribute for you, so it does not hit this at all unless you set SKIP_QUARANTINE_STRIP=1.

Reference

Every row below is read out of the source of v0.28.4. Filter across all six tables at once.

Keyboard shortcuts

Cmd on macOS, Ctrl on Linux and Windows. One binding covers both, because egui maps them to the same modifier.

KeysAction
Cmd EnterSend the active request. Ignored while a send is already in flight.
Cmd NNew draft request.
Cmd WClose the active tab.
Cmd DDuplicate the active tab.
Cmd SSave. A draft opens the save-to-folder dialog, a saved request writes and clears its unsaved marker.
Cmd FFind in the response body. Switches to the Body tab and focuses the search field.
Cmd KFocus the sidebar search field.
Cmd PRequest finder. Fuzzy-search requests across every collection.
Shift Cmd PActions palette. Every command in the table below, by name.
F2Rename the active request.
Up DownStep through the sidebar request list. Only while no text field has focus and no dialog is open, so typing is never hijacked.
EscClose the open dialog, palette, or inline search bar.
Cmd ,Preferences. macOS only, through the native menu bar.
Cmd OImport a collection file. macOS only, through the native menu bar.
Shift Cmd CToggle the code snippet panel. macOS only, through the native menu bar.

The last three are accelerators on the macOS NSMenu bar, which Linux does not get. On Linux, reach those three through the actions palette.

Actions palette

Open with Shift Cmd P and type. The palette matches on the name and on the extra search words listed here, so you do not have to remember the exact wording.

ActionAlso matchesKeys
New requestcreate add tabCmd N
Duplicate tabclone copy tabCmd D
Close tabclose windowCmd W
Toggle pin tabpin unpin sticky
Save draft to foldersave persist folder collectionCmd S
Copy as cURLcurl command line shell
Toggle code snippet panelcode panel side python javascript fetch httpieShift Cmd C
Open environmentsenv variables vars
Open settingspreferences timeout proxy tlsCmd ,
Paste cURL commandcurl import clipboard
Collection Runnerrunner collection run batch data rows csv json report
Workspace Syncsync git workspace openapi refresh import export
Import collection fileimport postman json yaml
Create workspace backupsnapshot restore data safety
Backupsrestore snapshot data safety location
Export all as JSONexport backup json
Export all as YAMLexport backup yaml
Clear historydelete wipe log
Toggle sidebar History and Collections viewswitch toggle sidebar history collections
About Rusty Requesterabout version credit help

Settings

Everything the Settings dialog exposes, with the value you get if you never open it. Settings are stored per workspace in data.json.

SettingDefaultRange and meaning
Request timeout 60 s 0 to 3600 seconds. 0 disables the timeout, so a request can hang until you cancel it.
Max response body 50 MB 0 to 2048 MB. Anything past the cap is discarded and the response shows a truncation banner. 0 removes the cap, and a large enough payload can then exhaust memory.
Proxy URL empty HTTP, HTTPS, or SOCKS5, for example http://proxy:8080. Empty means connect directly.
Verify TLS certificates on Turning it off accepts self-signed and expired certificates. Useful against an internal dev API, dangerous on the public internet.
Theme Dark Dark, Light, or Postman. Method colors and status pills are retuned per theme. The dialog previews the change before you save it.
Enable Workspace Sync off Opt-in local workflow for Git workspace import and export and OpenAPI refresh. While it is off, the app never reads or writes a Git workspace, and nothing runs in the background.
Check for updates on launch on One silent GET to the public latest.json per launch. Turn it off for zero outbound traffic at startup.

Code snippet languages

The snippet panel renders the active request in each of these. Snippets are redacted by default, so obvious secrets are masked while the request shape stays intact. Copying the raw version is a separate, explicit action.

LanguageForm
cURLShell command
PythonThe requests library
JavaScriptfetch
HTTPieShell command

Files on disk

PlatformWorkspace file
macOS~/Library/Application Support/rusty-requester/data.json
Linux~/.local/share/rusty-requester/data.json
Windows%LOCALAPPDATA%\rusty-requester\data.json

One plaintext JSON file holds collections, history, settings, and any token or password you typed into Auth or an environment variable. The app relies on your home directory's permissions to protect it. Do not commit it. A panic log and the update log are written beside it. If the file is ever unreadable at startup, the app sidelines it with a timestamped name rather than overwriting it, and tells you where it went.

Command line

FlagEffect
--version, -VPrint the version and exit without opening the window. Useful for confirming which build is actually on disk when Launch Services has cached an old one.

That is the whole command-line surface. Every other flag is ignored.

Platforms

Two release artifacts are built, and nothing else is published:

macOS
A universal disk image covering Apple Silicon and Intel, built on the GitHub macos-latest runner.
Linux
An x86_64 tarball, built on Ubuntu 22.04 so it links against glibc 2.35. That covers Ubuntu 22.04 and newer, Debian 12, Fedora 36 and newer, and RHEL 9. The build is pinned to 22.04 on purpose, because a binary built on a newer runner needs a newer glibc than many desktops have.
Linux on ARM
Not built. The installer refuses any Linux architecture other than x86_64 and tells you to build from source.
Windows
No release is published and the installer refuses to run. The source carries Windows branches and the app reads a Windows workspace path, so a local cargo build is the only route today. Whether Windows becomes a supported target is an open question, not a promise.

What the release contains

  • One binary. No bundled browser engine, no Node runtime, no separate helper processes. The interface is drawn by egui.
  • Built for size. The release profile uses opt-level = "z", link-time optimisation, a single codegen unit, and strips symbols. Actual artifact sizes are listed on each release, so read them from there rather than from a marketing number here.
  • 561 package entries in Cargo.lock. Count it yourself with grep -c '^\[\[package\]\]' Cargo.lock. That includes the app itself and every platform-specific and build-time dependency, so it is an upper bound on what any one target compiles.
  • Versioned with semver, pre-1.0. data.json reads forward through serde defaults, but a minor release can still change field shapes. The 1.0 line is where the on-disk schema, install paths, and export formats get locked.

Security

An API client sits on a trust boundary. You type a URL and a stranger's server sends bytes back. What the app guarantees about those bytes:

  • Response content is never executed. HTML renders as markup through egui, with no DOM and no JavaScript engine. A <script> tag is displayed as text.
  • Pasting a cURL command never runs a shell. The flags are parsed as data.
  • TLS and HTTP go through reqwest, hyper, and rustls, in safe Rust, which rules out the buffer-overflow class of bug a C client has to defend against.
  • Runner reports leave secrets out. Exported reports omit response bodies, headers, cookies, and extracted values, and redact query strings and fragments from URLs.
  • Sharing is redacted by default. Code snippets mask obvious secrets, and collection exports can be scanned and redacted locally before anything is written. Copying the raw version is always a separate, deliberate action.
  • No telemetry, no analytics, no account. The only outbound traffic is the requests you send, plus one optional update check that reads public release metadata. That check is a single switch in Settings.

What you still own: requests you aim at your own machine or internal network, files you save and then open in something else, and the fact that data.json and any exported collection folder are plaintext on your disk. A private Git repository is access control, not encryption. The full threat model and how to report a vulnerability are in SECURITY.md.