Hermit is an OpenAPI mock server. Pass it the path to a spec file, and it starts serving lightning-fast schema-accurate responses out of the box. No stubs to write, sensible defaults, configurable.
Hermit is useful whenever you need an API to be available but don't want to run the real backend:
- Frontend development -- build and iterate against real HTTP endpoints without depending on a live backend
- Integration and E2E testing -- run tests in CI against a predictable, schema-accurate server with no database or external services
- Contract validation -- verify that your OpenAPI spec produces the shapes your consumers actually expect
sequenceDiagram
participant Client
participant Hermit
participant Spec as OpenAPI Spec
Note over Hermit, Spec: Startup -- once (specs loaded in parallel)
Hermit ->> Spec: Read & parse YAML (one thread per spec file)
Hermit ->> Hermit: Resolve $refs, flatten allOf/oneOf
Hermit ->> Hermit: Pre-generate mock responses for all routes
Note over Client, Hermit: Runtime -- per request
Client ->> Hermit: GET /projects/{projectId}
Hermit -->> Client: 200 {"id": "abc", "name": "echo", ...}
Client ->> Hermit: POST /projects {"name": "my project"}
Hermit ->> Hermit: Merge request body into mock response
Hermit -->> Client: 201 {"id": "abc", "name": "my project", ...}
All schema work (ref resolution, composition, value generation) happens once at startup. Requests are served from an in-memory map with no I/O.
For POST, PUT, and PATCH requests, Hermit merges the fields you send into the mock response. This means your code
sees its own writes reflected back -- the most useful behavior for frontend development:
# Start Hermit
hermit --specs my-api.openapi.yml other-api.openapi.yml
# Create a project -- the response reflects the name you sent
curl -s -X POST http://localhost:8532/projects \
-H 'Content-Type: application/json' \
-d '{"name": "Acme Redesign", "status": "active"}' | jq .
# {
# "id": "foxtrot",
# "name": "Acme Redesign",
# "status": "active",
# ...
# }When a POST endpoint uses oneOf with a discriminator, Hermit inspects the request body to pick the right response
shape:
# Creating a "feature" task returns a FeatureTask shape
curl -s -X POST http://localhost:8532/projects/abc/tasks \
-H 'Content-Type: application/json' \
-d '{"type": "feature", "storyPoints": 8}' | jq .type
# "feature"
# Creating a "bug" task returns a BugTask shape
curl -s -X POST http://localhost:8532/projects/abc/tasks \
-H 'Content-Type: application/json' \
-d '{"type": "bug", "severity": "high"}' | jq .type
# "bug"Response field values are resolved in priority order:
| Priority | Source | When |
|---|---|---|
| 1 | Request body fields | POST, PUT, PATCH -- caller's values win, except for readOnly fields |
| 2 | example in schema |
Field has an explicit example value (if --use-examples) |
| 3 | default in schema |
Field has a default value and no example (if --use-examples) |
| 4 | Random value | Fallback -- random word, number, boolean, or format-aware value (UUID, date-time, β¦) |
Fields marked readOnly: true in the schema are never overridden by request body values. Fields marked
writeOnly: true are excluded from generated responses entirely.
See install.md.
See cargo.md.
See docker.md.
Run Hermit against your spec (replace the path with your actual spec file):
hermit --specs ~/Documents/dev/hermit/specs_assets/taskflow.openapi.ymlYou can point to a directory containing multiple specs to load them all at once -- Hermit merges their routes and loads them in parallel:
hermit --specs-dir ~/Documents/dev/hermit/specs_assetsTo see what arguments are available, run:
hermit --helpStop the server with Ctrl+C, or if it's running in the background:
kill $(lsof -ti :8532)Replacing the port number at need.
See options.md.
See PRIVACY.md.
See UNLICENSE.
And now some dev stuff
Load multiple specs in one command:
cargo run --release -- --specs-dir specs_assetsThe server listens on port 8532 by default. Override with --port.
To see what arguments are available, run:
hermit --helpInstall just:
cargo install justInstall dev tools:
just setupIn RustRover, go to Settings > Version Control > Commit > Advanced commit checks and choose the pre-commit
configuration to run these checks automatically on commit.
Explore justfile for available commands.
Requires the server to be running. Run with Bruno:
cd api_tests/hermit_api_tests && npx --yes @usebruno/cli run --env hermit_env --reporter-html test_report.html --reporter-json test_report.jsonSee docker.dev.md.
See architecture.dev.md.
See docs/dev