apic-gui Rizki Rakasiwi
winget install --id=rizukirr.apic-gui -e apic-gui is the desktop front-end for apic, built on the shared apic-core, for designing, validating, and collaborating on API contracts with a graphical interface.
winget install --id=rizukirr.apic-gui -e apic-gui is the desktop front-end for apic, built on the shared apic-core, for designing, validating, and collaborating on API contracts with a graphical interface.
A Free, Full Open Source Git-able api contract tools. Apic stores your API contracts as plain JSON in your repo, so they're diffable, reviewable, and versioned like any other code. No paywalled seats or separate workspaces, if a teammate can clone the repo, they can collaborate on the contract.
CLI, TUI, and desktop GUI, all over one shared core (apic-core), so every interface edits the same files and never drifts.
> ## ROADMAP
> - Distribution
> - Aur
> - Copr
> - Launchpad
> - Flatpak
> - Winget
> - Homebrew
> - Git GUI
Mainstream API tooling gates collaboration behind paywalls, charging per team member just to share a workspace. Because apic contracts are plain JSON in your repo, your existing Git workflow is the collaboration layer:
git push. Everyone with repository access already has full collaboration capabilities.git blame.apic read renders your contracts into clean, colorized tables directly in your shell.apic ships as two binaries that share one core: apic (the CLI/TUI) and
apic-gui (the desktop app). Install either or both.
yay -S apic-bin (or paru -S apic-bin) — ships both binaries.sudo dnf copr enable rizukirr/apic && sudo dnf install apic-cli apic-gui.flatpak install io.github.rizukirr.apic (GUI)winget install rizukirr.apic (CLI) · winget install rizukirr.apic-gui (GUI). The GUI installs as an MSI that adds an apic entry to the Start menu and an uninstaller in Settings → Apps.apic)crates.io (recommended):
cargo install apic-cli
From source (requires a Rust toolchain, 1.88+):
git clone https://github.com/rizukirr/apic
cd apic
cargo install --path .
To run without installing, use cargo run -- from the project directory.
apic-gui)crates.io:
cargo install apic-gui
cargo install only puts the binary on your PATH. On Linux, run
apic-gui --desktop-entry once to add it to your application launcher.
On Linux, building the GUI needs the system X11/Wayland/GL development libraries
(on Debian/Ubuntu: libxkbcommon-dev, libwayland-dev, libxcb1-dev,
libgl1-mesa-dev, and friends). macOS and Windows build with no extra packages.
At runtime, the Linux GUI opens folders/files through your desktop's portal. If
the Open/New dialogs never appear, install a portal and a backend, e.g.
xdg-desktop-portal plus xdg-desktop-portal-kde (KDE) or -gtk (GNOME/other).
Grab the archive for your platform from the
latest release, verify the
.sha256 checksum, extract, and put the binary on your PATH. Each release
provides apic- (CLI) and apic-gui- (GUI) archives. CLI
builds cover Linux (x86_64, aarch64), macOS (Intel, Apple Silicon), and Windows
(x86_64); GUI builds cover the same platforms (arm64 Linux is best-effort).
# 1. Initialize a project in the current directory (creates .apic/config.toml)
apic init
# 2. Point apic at the folder that holds your contract files (Optional)
apic config --set-dir api-contract
# 3. Edit the default template, or author a new named one
apic open --template # edit .apic/template/convention.json
apic create --template mobile # author .apic/template/mobile.json
# 4. Scaffold a new contract (opens the interactive editor)
# uses the only template, prompts to pick when several exist, or
# --use-template chooses one; falls back to the built-in template
apic create -f auth/login.json
apic create -f auth/login.json --use-template mobile
# 5. List and read contracts
apic list
apic read -f login
apic create and apic open open an interactive terminal editor
(TUI) by default. It shows the contract exactly as apic read renders it, the
same header, sections, tables, and inline JSON examples, and lets you edit in
place:
↑/↓ (or j/k) select a row; Enter steps into the row's cells;
←/→ (or h/l) move between cells; Esc steps back out. METHOD url line. Enter on it focuses
the method; Enter there opens a method picker (j/k to choose, Enter
to select, Esc to cancel). l moves to the URL, edited inline with Enter/i.QUERY and HEADERS are NAME/VALUE(/DESCRIPTION) tables.
a adds a row and drops you into it; d deletes the selected row after a
confirmation. A row you add and then cancel while still empty is discarded.a in REQUEST opens the JSON editor (creating the body);
an empty body reads as (none).RESPONSE is a code - title tab strip. a opens a small
Status / Short Description form, then the JSON editor for the new response.
e on a tab re-opens that form to edit its status/title; e (or Enter) on
the JSON opens the editor. d removes the whole response.Ctrl-P pretty-prints it, Ctrl-S
saves, Esc cancels. Saving an empty body removes its response.Ctrl-S saves the contract; Esc/q exits; ? shows the
full key map.Prefer your own editor? Pass --editor to open the file in $VISUAL/$EDITOR
(or a specific one, e.g. apic open login --editor "code --wait").
apic-gui works on the same .apic projects as the CLI, on the exact same JSON
files, both are thin layers over the shared apic-core crate. Run it, then
Open a project folder (or New to create one); it reopens the last
project on the next launch.
apic-gui
What it does:
A template is a starter contract that apic create -f copies from
when you scaffold a new endpoint. apic init seeds one at
.apic/template/convention.json from the built-in default; a project can hold
several named templates (apic create --template authors more), and
--use-template chooses which one seeds a new contract (apic create
prompts when several exist). A template is never overwritten once it exists.
The project template is overlaid onto the built-in default, so it only needs
to carry the fields you want to standardize, it can be a small partial contract.
It lives in .apic/template/, committed to the repo like everything else, so the
whole team scaffolds from the same starting point.
The template is the single thing every new contract inherits from, so it is where a team's shared API conventions belong. Encode the general design once and every endpoint starts consistent, with none of the boilerplate re-typed:
https://api.example.com/v1/... (or a
{{baseUrl}}/{{base_path}}/... placeholder), so every endpoint targets the same
host and version.Content-Type,
Authorization: Bearer {token}, a DeviceID/AppID, each with its required
flag set the way your API expects.{ "statusCode", "message", "error", "value" }), put that shape in the
template's example responses so new endpoints follow it by default.page, limit) or filter keys that
most list endpoints share.Because scaffolding always starts from these defaults, the template turns your API design guidelines into something executable: consistency becomes the path of least resistance, drift shows up as a diff in review, and adding an endpoint is "edit what's different" instead of "remember every convention". When the convention itself changes, you edit one file and every new contract picks it up.
apic init [--set-dir ]Initializes an .apic project in the current directory by creating
.apic/config.toml. The optional --set-dir records which directory contract
files are scanned from (defaults to the current directory).
apic config [--set-dir ]Updates project configuration.
--set-dir , change the working directory that contracts are scanned
from (must exist).apic create (-f | --template ) [--use-template ] [-e ]Creates a new contract (-f) or authors a new template (--template).
With -f , a contract is seeded from a project template and opened in
the interactive TUI; the file is written only when you save. A relative path is
resolved against the configured working directory, and apic refuses to
overwrite an existing file. When .apic/template/ holds a single template it is
used; when it holds several you are prompted to pick one (an inline picker), and
--use-template selects one directly (fuzzy-matched) to skip the prompt.
With no usable template, the built-in default is used.
With --template , a new template is authored at
.apic/template/.json (a flat name), seeded from the built-in default or,
with --use-template , from an existing template. It opens in the TUI and
refuses to overwrite an existing template. --template and -f are mutually
exclusive; --use-template composes with either.
apic create -f auth/login.json # contract from the project template
apic create -f auth/login.json --use-template mobile # contract from the `mobile` template
apic create --template mobile # author a new template
apic create --template mobile --use-template convention # seed it from `convention`
Pass -e/--editor to scaffold the file to disk and open it in your external
editor instead of the TUI. Editor resolution order: --editor flag → $VISUAL
→ $EDITOR → vi. The flag picks the editor for a single invocation (e.g.
apic create -f auth/login.json -e nano) and the value may include arguments.
GUI editors need their wait flag (code --wait, subl -w) so apic waits for
the file to be saved.
apic list [--filter ] [--absolute ]Lists discovered .json contract files under the working directory.
--filter , show only contracts whose path fuzzy-matches the query,
best match first (e.g. apic list --filter user).--absolute , print absolute paths or paths relative to the
working directory (false, the default).apic read -f [-s ]Renders a contract as formatted tables. -s filters the response
section to a single HTTP status code.
`` is resolved flexibly, an exact match wins, then fuzzy:
user/user.json.json extension, user/user, auth/loginuser, lognapic read -f user/user.json # exact path
apic read -f auth/login # extension optional
apic read -f login # fuzzy
apic read -f login -s 401 # show only the 401 response
apic read --template # render the project template
It prints the endpoint header (name, description, and the METHOD url line),
the QUERY and HEADERS tables, and the request/response bodies as their inline
JSON example payloads:
REQUEST
{
"agentCode": "79009901",
"password": "newPassword123!"
}
RESPONSE 200 — OK
{
"statusCode": 200,
"message": "Login berhasil",
"value": { "accessToken": "...", "tokenType": "Bearer" }
}
apic open (-f | --template) [-e ]Resolves `` exactly like read (path, extensionless, or fuzzy) and
opens the matching contract in the interactive TUI. Pass -e/--editor to open
it in your external editor instead, the same editor resolution as apic create.
Pass --template instead of -f to edit the project template in
.apic/template/ that apic create scaffolds from (the sole template, or
convention.json by default); it is seeded from the built-in default first if
none exists yet. --template and -f are mutually exclusive, and exactly one
is required. To author a new named template, use apic create --template .
apic open -f user/user.json
apic open -f user
apic open -f user -e nano # open with a one-off editor
apic open --template # edit the project template
Output is colorized when stdout is a terminal and plain when piped, so it stays clean in scripts. Contract strings are sanitized before display, so a file from an untrusted source cannot inject terminal escape sequences.
apic remove (-f | --template )Resolves `` exactly like read/open (path, extensionless, or
fuzzy, prompting to pick when ambiguous) and deletes the matching contract
file. On an interactive terminal it asks Remove ? [y/N] first and only
deletes on y/yes; when stdin/stdout is not a terminal (scripts) it removes
without prompting.
Pass --template instead of -f to remove a project template from
.apic/template/ (fuzzy-matched the same way, with the same confirmation). No
template is protected — removing convention.json or the last template is
allowed; apic create reseeds convention.json from the built-in default next
time. --template and -f are mutually exclusive.
apic remove -f user/user.json
apic remove -f login # fuzzy, with confirmation
apic remove --template mobile # remove a project template
apic validate [-f ] [--template]Checks that contracts parse and match the required contract format. With no -f, every
contract under the working directory is checked. A query ending in / (e.g.
auth/) validates every contract under that folder, recursively; otherwise the
query resolves to a single contract like read (path, extensionless, or fuzzy).
Prints ok/FAIL per file with the parse error (line and column) for failures,
and exits non-zero if any contract is invalid, so it drops straight into a
CI step or pre-commit hook.
apic validate # check every contract
apic validate -f login # check one
apic validate -f auth/ # check every contract under auth/, recursively
apic validate --template # check the project template (in .apic/template/)
ok auth/login.json
FAIL user/user.json: EOF while parsing an object at line 12 column 1
2 passed, 1 failed
apic convert --postman [--destination ]Imports a Postman collection as apic contracts, one JSON file per request, mirroring the collection's folder nesting. Accepts Postman Collection exports of v1.0.0, v2.0.0, and v2.1.0 (auto-detected).
--postman , the Postman collection JSON to import.--destination , where to write the contracts, relative to the working
directory (created if missing). Optional, defaults to the working
directory itself. The path is confined to the working directory (../absolute
escapes are rejected). An existing contract is left untouched (the import
errors) unless --force is passed.--force, overwrite contracts that already exist instead of erroring.Each Postman folder becomes a directory and each request becomes
folder/request_name.json. Only the fields apic models are imported (method,
URL, headers, request/response bodies), Postman-specific data (auth blocks,
scripts, events, variables) is ignored. A request whose HTTP method apic does
not model (anything other than GET/POST/PUT/PATCH/DELETE/HEAD/
OPTIONS) is imported as GET with a warning, so nothing is downgraded
silently.
apic init # an apic project is required
apic convert --postman MyAPI.postman.json # writes into the working directory
apic convert --postman MyAPI.postman.json --destination imported
apic convert --postman MyAPI.postman.json --force # overwrite existing contracts
warning: request "Preflight" uses method TRACE, unsupported by apic — imported as GET
Converted 12 contract(s) into imported (1 warning)
apic treats contract files and paths as untrusted, so it is safe to run
against contracts from any source:
apic create refuses paths that escape the working
directory via .. or an absolute path elsewhere.A contract is a single JSON object describing one endpoint. See
apic-core/src/templates/contract.json
for the built-in template apic create seeds from (and Templates
for how to make it your own), or example/ for complete projects.
{
"name": "update-user",
"description": "Update a user",
"method": "PUT",
"url": "https://api.example.com/users/{id}",
"query": [
{
"name": "notify",
"value": "true",
"description": "Send a notification email",
"required": false
}
],
"headers": [
{ "name": "Content-Type", "value": "application/json", "required": true },
{ "name": "Authorization", "value": "Bearer {token}", "required": true }
],
"request": {
"name": "Rizki Rakasiwi"
},
"responses": [
{
"code": 200,
"description": "User updated",
"headers": [
{ "name": "X-Request-Id", "value": "abc-123", "required": false }
],
"schema": {
"status": 200,
"message": "OK"
}
}
]
}
A body is a raw JSON payload, the exact thing you would send or receive. The
request body is written directly under request; a response body is written
under the response's schema key. There is no separate field-level schema:
the payload is the contract's source of truth for a body's shape, and apic read
prints it verbatim. Omit request (or a response's schema) when there is no
body.
| Field | Required | Description |
|---|---|---|
name | yes | Endpoint name. |
description | no | Short description of the endpoint. |
method | yes | HTTP method: GET, POST, PUT, PATCH, DELETE, HEAD, or OPTIONS. |
url | yes | Request URL as a single free-form string, e.g. https://api.example.com/users/{id}. Path parameters are written inline as {name} tokens. |
query | no | Array of query parameters; see below. |
headers | yes | Array of request headers; see below. |
request | no | Request body: the raw JSON payload, written directly. Omit it when the endpoint has no body. |
responses | yes | Array of responses; see below. |
Each query parameter:
| Field | Required | Description |
|---|---|---|
name | yes | Parameter key, e.g. page. |
value | no | Example value, e.g. 2. |
description | no | What the parameter is for. |
required | no | Whether the parameter is required (default false). |
Each header (request or response):
| Field | Required | Description |
|---|---|---|
name | yes | Header name, e.g. Authorization. |
value | yes | Example value, e.g. Bearer {token}. |
required | no | Whether the header is required (default false). |
Each response:
| Field | Required | Description |
|---|---|---|
code | yes | HTTP status code, e.g. 200. |
description | yes | Short description, e.g. OK. |
headers | no | Array of response headers (same shape as request headers). |
schema | no | The response body: the raw JSON payload for this response. |
Path parameters are not a separate section: write them inline in the url
string as {name} (e.g. {id} in .../users/{id}).
> The request body has no wrapper key, it is the JSON value itself. A response's
> body lives under schema (not example). Contracts written for the older
> { "example": ... } body shape do not carry over and must be updated.
apic init writes .apic/config.toml:
name = "apic"
version = "0.1.0"
[root]
working_dir = "api-contract"
working_dir is stored relative to the project root, so .apic/config.toml
is safe to commit and share, it resolves correctly on any clone. apic
locates the project by walking up from the current directory to find the
.apic directory, so commands work from anywhere inside the project tree.
Licensed under the MIT License.