Skip to content

Repository files navigation

Apilator

A REST API testing client for Windows. Tabs, request history, proxy support and a response viewer that stays responsive on large payloads.

Built with Tauri v2, React 18 and TypeScript.

Features

  • Requests — GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS with headers, query params and raw or form-encoded bodies
  • Auth — Basic, Bearer and JWT (HMAC: HS256/384/512), as an Authorization header or a query parameter
  • Bodies — raw (JSON, XML, HTML, text), URL-encoded forms, and multipart/form-data with file uploads
  • Tabs — rename, colour, pin, reorder, duplicate, and reopen a closed tab with Ctrl+Shift+T
  • Response viewer — JSON, XML, HTML, hex and base64 views, line numbers, and search that stays usable on multi-megabyte responses
  • Collections — saved requests in folders, any depth, rearranged by drag and drop, kept in their own file
  • Environments — dev, staging and prod variable sets, used as {{name}} anywhere in a request; variables marked secret live in the Windows Credential Manager, not in the file
  • Import and export — share collections as a file, or import an OpenAPI 3 document (JSON or YAML), which arrives grouped into folders by tag with example bodies filled in
  • History — the last 50 requests, grouped by day, one click to load one back into a tab
  • Proxy — system, environment or a custom proxy with authentication
  • Security — TLS certificate verification on by default with an explicit opt-out, and proxy passwords kept in the Windows Credential Manager rather than on disk

Install

Download from the latest release. There are two installers and the difference matters:

File Installs for Needs administrator
Apilator_x.y.z_x64-setup.exe the current user no
Apilator_x.y.z_x64_en-US.msi the whole machine yes

Use the -setup.exe unless you specifically want a machine-wide install. The MSI fails with error 1603 when run without elevation, which is what an unprivileged silent install looks like.

Neither installer is code-signed, so Windows SmartScreen warns the first time: choose More info, then Run anyway.

Once installed, Apilator checks GitHub for updates in the background and offers them. Update packages are signed and verified against a key built into the app, so an update can only come from this project. Nothing is downloaded or installed without you asking.

Requirements

  • Windows 10 or 11
  • Bun
  • Rust with the MSVC toolchain
  • WebView2 runtime (already present on current Windows installs)

Development

bun install
bun run dev

Quality gates, all of which run in CI:

bun run typecheck   # tsc --noEmit
bun run lint        # eslint
bun run test        # vitest
bun run check       # all three

cargo clippy --manifest-path src-tauri/Cargo.toml --all-targets -- -D warnings
cargo test --manifest-path src-tauri/Cargo.toml

A handful of Rust tests hit the network (certificate handling, response size limits) and are excluded from the default run:

cargo test --manifest-path src-tauri/Cargo.toml -- --ignored

Build

.\scripts\build.ps1            # EXE + MSI installer
.\scripts\build.ps1 -ExeOnly   # EXE only, faster
.\scripts\build.ps1 -OpenFolder

Output:

  • target/release/apilator.exe — standalone, runs without installing
  • target/release/bundle/ — MSI and NSIS installers

The version lives in three files that must agree: package.json, src-tauri/tauri.conf.json and src-tauri/Cargo.toml.

Releasing

Push a version tag and GitHub Actions does the rest:

# bump the version in package.json, src-tauri/tauri.conf.json and src-tauri/Cargo.toml
git tag v0.9.0
git push origin v0.9.0

The workflow builds the installers, signs the update package and publishes a GitHub Release including latest.json, which is what running copies check against.

It needs two repository secrets, produced by bunx tauri signer generate:

Secret Contents
TAURI_SIGNING_PRIVATE_KEY the private key file's contents
TAURI_SIGNING_PRIVATE_KEY_PASSWORD its password

Generate the key with a real password. tauri signer generate -p "" does not produce a password-less key, it produces one that then refuses to sign.

Losing the private key means existing installations can no longer verify updates and would have to be reinstalled by hand. Keep a backup outside the repository.

Where things live

Layer Directory Responsibility
Views src/views/ React components, rendering only
Hooks src/hooks/ UI logic, the only place views reach the backend through
Stores src/stores/ Zustand state and the logic around it
Services src/services/ Tauri and external integrations
Domain src/domain/ Types, factories and pure logic; framework-free
Backend src-tauri/src/ Rust: HTTP client, persistence, secrets, JWT

The point of the layering is not tidiness. It is that the interesting logic — the collection tree, variable substitution, state migration, request building — can be tested without rendering anything, and that a change to the UI cannot quietly reach into the network layer.

Layer May import May not import
Views stores, hooks, domain, other views services, @tauri-apps/*
Hooks stores, services, domain views
Stores services, domain views
Services domain, Tauri APIs stores, views, hooks
Domain nothing everything else, frameworks included

ESLint enforces this, it is not just documentation: the no-restricted-imports rules in eslint.config.js fail the build when a view imports a service or the domain imports a framework. A new violation cannot land unnoticed — the rule caught one during the refactor that introduced it, which a manual review had missed.

When adding something, put the logic as far down as it will go. Anything in domain/ or utils/ can be tested directly, which is why those layers carry the highest coverage requirements.

Domain

Pure TypeScript. No framework imports, no I/O, and the most thoroughly tested layer, because everything interesting can be checked without rendering anything.

Module Contents
request.ts / response.ts HttpRequest, HttpResponse, request state union
auth.ts auth configs and the header they produce
tab.ts / history.ts tabs, history entries
collection.ts the collection tree and its operations (find, insert, move, remove)
environment.ts environments and {{variable}} substitution
openApi.ts OpenAPI 3 document to collection
settings.ts theme, proxy and general settings

Services

Everything that talks to the Rust backend or the outside world. Services may use Tauri APIs but know nothing about stores, views or hooks.

Module Responsibility
httpService building and sending requests, variable substitution, JWT signing
persistenceService app state: load, save, migrate, and back up rather than delete
collectionsService collections file, plus export and import
environmentsService environments file, keeping secret values out of it
secretsService the Windows Credential Manager
fileService / systemService file dialogs, app and OS info

Stores

Zustand. State plus the logic around it; they call services, never the other way round.

Store Responsibility
useTabsStore open tabs, the closed-tab stack, reordering
useHistoryStore the last 50 requests, as summaries
useCollectionsStore the collection tree, persisted on every change
useEnvironmentsStore environments, selection and secret handling
useSettingsStore theme, proxy and general settings

Backend

Module Responsibility
http_client.rs pooled reqwest clients, streaming reads, cancellation, multipart
persistence.rs atomic writes and backups for every data file
secrets.rs Windows Credential Manager
jwt.rs HMAC JWT signing
system_proxy.rs the Windows proxy setting, so credentials can be attached

Application data lives in %LOCALAPPDATA%\Apilator\:

File Contents
apilator-state.yaml open tabs, request history
apilator-collections.yaml saved requests
apilator-environments.yaml environments and non-secret variables

Secret values — proxy passwords and variables marked secret — are never written to these files. They go to the Windows Credential Manager.

Icons

assets/app_icon_trimmed.png is the master artwork. Everything under src-tauri/icons/ is generated from it and should not be edited by hand:

bunx tauri icon assets/app_icon_trimmed.png

Regenerate from the master, not from src-tauri/icons/icon.png — that file is itself an output, squared off and downscaled, so using it as the input loses a little more each time.

Licence

MIT

About

A REST API testing client for Windows. Tauri + React + TypeScript.

Resources

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages