Getting started
From an OpenAPI spec to a served response, in about a minute.
You need the apifae binary — see Install — and a directory
containing an OpenAPI 3.x or Swagger spec. If you want to follow along exactly,
download the manual's own fixture,
orders.openapi.yaml:
mkdir orders && cd orders
curl -fsSL https://apifae.com/manual/fixtures/orders.openapi.yaml -o openapi.yaml
It is four endpoints and fits on one screen. Working from a clone of the
repository, cp docs/manual/fixtures/orders.openapi.yaml ./openapi.yaml is the
same file.
1. Initialise the workspace
$ apifae init -N
✓ Project 'orders' initialized successfully!
Created:
✓ Created apifae.yaml
✓ Created schemas
✓ Created mocks
✓ Created schemas/openapi.yaml
✓ Created mocks/…
✓ Created mocks/…
✓ Created scenarios/from-spec.yaml
Next steps:
1. apifae serve # Start mock server
2. apifae validate # Validate schemas
Happy mocking!
EXIT: 0
init found the spec by itself — no flag, no path argument. It copied it to
schemas/ and wrote one mock per documented path — here mocks/orders.yaml
and mocks/reports/daily.yaml, one per path group.
-N is the non-interactive form. It imports the spec exactly as the prompt does,
and it is what a Dockerfile or a CI step runs.
The mocks are populated, not stubbed. Every property in those files comes from
the spec's own example: values, which is why the next step serves something
believable rather than {}.
Each declared error response is generated too. The spec documents a 404 on
GET /orders/{id}, so a 404 exists — reachable through a scenario rather than
by default, since a mock that 404s by default is not much of a mock. See
Scenarios.
2. Check it
$ apifae validate
Loading OpenAPI spec from …/openapi.yaml...
→ Orders API v1.0.0
Loading mocks from mocks...
→ 4 endpoints from 2 files
Validating mocks against OpenAPI spec...
4 mocks checked, 4 valid, 0 errors, 0 warnings
✓ All mocks valid
EXIT: 0
validate renders every template and type-checks the result against the spec, so
this is a stronger statement than "the YAML parses".
3. Serve it
$ apifae up
✓ APIFae mock server running at http://127.0.0.1:4000
Loaded 4 endpoints from 2 files
Watching for changes...
Leave it running. It watches the workspace, so editing a mock is reflected on the next request — no restart.
4. Use it
Every endpoint the spec documents is live, at the status the spec declares:
curl http://127.0.0.1:4000/orders
{"data":[{"createdAt":"2026-08-01T09:15:00Z","currency":"EUR","customerEmail":"ada@example.com","id":"ord_8f14e45fceea","note":"Leave with the concierge","status":"paid","total":4250}],"hasMore":false,"page":1,"total":3}
The four endpoints answer like this:
| Request | Status |
|---|---|
GET /orders |
200 |
GET /orders/ord_42 |
200 |
POST /orders |
201 |
GET /reports/daily |
500 |
POST /orders returns 201 and /reports/daily returns 500 because that
is what the spec declares. /reports/daily documents no success response at all,
so its mock is the 500 — the tool is not inventing a happy path the contract does
not describe.
5. Error states, without a second workspace
The 404 from step 1 lives behind a scenario:
$ apifae scenario list
Scenarios:
getOrder-404
GET /orders/{id} responds 404 (declared in the OpenAPI spec)
EXIT: 0
Activate it against the running server, and GET /orders/{id} starts returning
404 until you reset:
apifae scenario set getOrder-404
apifae scenario reset
One workspace, several API conditions. See Mock an API before it exists for the states worth building, and Scenario files for the file format.
Your mocks are only as good as your spec's examples. In this fixture the
404and the500share oneErrorschema, whoseexample:values readreport_failed/ "Report worker is not available". So the 404 body says the report worker is unavailable, which is nonsense for a missing order. APIFae copied the spec faithfully; the spec is what is vague. Give an error response its ownexample:when you want its mock to be specific.
6. Keep it honest
This is the part that makes APIFae different from writing the mocks by hand.
Point diff at the real API and it will tell you whether
your mocks — and your spec — still describe it:
apifae diff https://api.example.com
That is a guide of its own: Keep a mock honest.
Where things live
orders/
├── apifae.yaml the workspace config
├── openapi.yaml the spec — this is the one commands read
├── mocks/ one file per path group
│ ├── orders.yaml
│ └── reports/daily.yaml
├── scenarios/from-spec.yaml named states
└── schemas/openapi.yaml where init puts the spec it imported
Where the spec is looked for, in this order: openapi.yaml, openapi.yml
or openapi.json at the workspace root, then the schemas: globs in
apifae.yaml. validate, up, patch and diff all resolve it the same way,
so the copy init writes into schemas/ is found without you moving anything —
and while a root spec exists, it is the one that counts.
A schemas/ directory holds shared fragments too; only a file that declares
itself with a top-level openapi: or swagger: key is treated as the spec, and
when several do, the first in sorted order wins.
It is all text, and it is all meant to be committed. Sharing a workspace with your team means committing it to git — there is no hosted service, and the four commands that name one refuse rather than pretend. See Commands that refuse.