Commands
Every command the binary answers to, what it is for, and when to reach for it.
This page is an index, not a reference: it says what each command is for. The
exhaustive flag-by-flag reference — every option, its default and its value name,
plus what each exit code means — is generated from the binary's own argument
declaration and lives in reference.md.
APIFae ships fifteen commands. Eleven do work. Four name a hosted service that does not exist yet and refuse rather than pretending — they are listed at the bottom, under Commands that refuse, and are the honest edge of the tool rather than a gap in this page.
Exit codes follow one rule everywhere: 0 succeeded, 1 the command ran and
found a problem, 2 you asked for something impossible — an unknown flag, a
missing argument. Where a command means something more specific by 1, its entry
says so.
The daily loop
init
Turns a directory into an APIFae workspace. It looks for an OpenAPI 3.x or
Swagger spec where you are — openapi.yaml, swagger.json, api/*.yaml and
friends — copies it to schemas/, and writes one mock per documented path,
populated from the spec's own example: values.
Reach for it once, first. The point is that init then up serves the
documented API immediately, rather than leaving you a directory of stubs to fill
in.
$ apifae init -N
EXIT: 0
-N is the non-interactive form and imports the spec exactly as the prompt
does. It is what a Dockerfile or a CI step runs.
With no spec in the directory, init writes a single commented example mock
instead, and the workspace still serves.
up
Starts the mock server, watching for changes. This is the command you leave running in a terminal all day; edit a mock and the next request reflects it.
$ apifae up
up does not return: it serves until you stop it. There is no exit status to
gate on, which is why a pipeline runs validate or
diff rather than this.
serve
The same mock server as up. up is the quick-start spelling and
serve the explicit one; they run the same code.
Reach for serve in scripts and CI, where the more descriptive name reads
better, and for up when you are typing it yourself.
validate
Checks every mock in the workspace: that it loads, that its templates render, and that what it renders agrees with the spec.
Reach for it before you commit, and in CI. It exits 1 on an error — a mock that
disagrees with the spec, or a file that will not load. Mocks the spec does not
describe are warnings and exit 0, unless you pass --strict.
$ apifae validate
EXIT: 0
If there is no spec in the workspace, validate says so and checks the mocks on
their own terms rather than refusing.
status
Reads the workspace you are standing in and reports it: project, mock and schema counts, defined scenarios, and whether a server is currently serving this workspace.
Reach for it when you are not sure what a directory contains, or from a script —
--json gives the same reading in a machine-readable form.
$ apifae status
EXIT: 0
Keeping a mock honest
diff
Compares your mocks against a live API, and the live API against your spec. Two independent questions, which is the point: a mock can match production perfectly while both have drifted away from the contract the spec describes.
Reach for it as a CI gate, and whenever you suspect the real API has moved.
$ apifae diff https://api.example.com
Its exit codes carry more meaning than the general rule:
| Exit | Meaning |
|---|---|
| 0 | clean |
| 1 | drift, a contract violation, or both |
| 2 | the run could not complete — connection refused, timeout, 401, 403 |
Separating 1 from 2 is what makes it usable as a gate: a network problem must not read as a passing contract, and it does not.
Every response variant is probed. A response carrying a when: block is
compared against a request built to satisfy that block, and reported under its
own label; see the FAQ for what
it cannot build a request for.
Endpoints and variants that could not be checked are reported but do not fail
the run unless you pass --fail-on-skip.
patch
Applies what diff found, rewriting only the fields that actually changed.
Reach for it after a diff you believe. It edits in place and preserves the file
around the change — comments, quoting and key order all survive — so the
resulting commit shows the drift and nothing else. --dry-run changes nothing;
every applied change leaves a timestamped .bak.
$ apifae patch https://api.example.com --dry-run
Under --dry-run it exits 1 when it finds drift — finding it is the whole
point, and the exit code is what a CI gate reads. A real run exits 0 once it has
applied everything it found, and 1 only when something it found could not be
written. Either way, a 1 from patch is not a failure to run; that is 2.
It will not write a value the spec forbids unless you pass
--accept-violations.
record
Proxies a real API and captures the traffic through it into mock definitions, including HTTPS by way of a generated CA certificate.
Reach for it when the API already exists and writing mocks by hand is the wrong way to spend an afternoon — and when you want a replayable capture of what production actually returned.
$ apifae record https://api.example.com
ca
Inspects and removes the recording CA certificates APIFae has written on this
machine. record asks you to trust a root certificate; this is how you see what
that left behind and take it back out.
It reads what APIFae wrote on disk. It cannot see your system trust store, and says so rather than implying otherwise.
ca list
Lists the recording CAs APIFae has written on this machine.
$ apifae ca list
EXIT: 0
ca remove
Deletes a recording CA and prints how to untrust it. Removing the file does not untrust the certificate — that needs your system's own tooling, which the command spells out for you.
Scenarios
scenario
Named states one workspace can be in — empty, forbidden, slow — so the same
mocks can stand in for several API conditions without a second workspace.
Reach for scenarios when you are testing what your client does when things go wrong, which is most of the interesting testing.
scenario list
Lists the scenarios this workspace defines.
$ apifae scenario list
EXIT: 0
scenario set
Activates a scenario on a running server.
scenario reset
Returns to the default state, with no scenario active.
scenario create
Writes a new scenario file.
Configuration
config
Reads and writes the workspace's apifae.yaml.
Reach for config rather than editing the file when you want the effective
value — the one the tool will actually use once defaults, the config file and any
--config override have been resolved.
config list
Shows the effective configuration, annotated with where each value came from.
$ apifae config list
EXIT: 0
config get
Shows one key's effective value and its source.
config set
Sets a value.
config add
Appends to a list key, such as schemas.
config remove
Removes a list item, or deletes a map entry such as auth.headers.X-Api-Key.
Commands that refuse
login, logout, push and pull name APIFae's hosted service. That service
does not exist yet. These commands are on the surface because the names are
real intentions and part of the intended workflow, but each exits non-zero with a
message saying so.
They used to print a ✓ and exit 0 having done nothing. That was worse than
useless, so it is gone: a command that refuses honestly is not a false claim.
Nothing in the local workflow needs an account. init, up, record, diff,
patch, validate and scenario all work against files in your workspace.
Sharing a workspace with your team today means committing it to git.
login
Would authenticate against APIFae cloud.
$ apifae login
EXIT: 1
logout
Would end that session.
push
Would upload local schemas to a hosted workspace.
pull
Would download them.