Guides

Seed a Mock Library

Gostly normally fills its mock library by recording real traffic in LEARNmode. But on day one you have an empty library and nothing to serve — and some upstreams (paid APIs, partner sandboxes, third-party gateways) you can't drive on demand. Seeding fixes the cold start: import a HAR, Postman collection, or OpenAPI spec and the proxy has mocks to serve before a single request flows through it.

The empty-library problem

The recorded path works the moment traffic flows. Seeding covers the gap before it does. A seeded mock is the same shape as a recorded one — once it's in the library, the serving cascade, fidelity scoring, and drift detection can't tell a seeded mock from a recorded one. The only difference is provenance: each seeded row carries a source tag of seed_har, seed_postman, or seed_openapi.

HAR

Highest fidelity

An HTTP Archive export from browser DevTools, mitmproxy, or Charles. Every byte was on the wire, so the seeded response is production-accurate.

Postman

Medium fidelity

A Collection v2.1 export with saved example responses. Curated by the API publisher — mostly hand-vetted, some synthetic. Folder + variable resolution is handled.

OpenAPI

Schema-driven

An OpenAPI 3.x spec (JSON or YAML). Bodies are synthesised from example / examples / a schema walk, so fidelity is lowest — but coverage is broadest.

Seeding from the dashboard

The operator dashboard has a drag-drop seeding page. Drop a file, pick the target service, pick a format, and commit. When the file parses as JSON the format is auto-detected from its top-level shape; YAML specs are picked manually. The steps:

Drop a file

Drag a .har, .json, .yaml, or .yml file onto the drop zone (or browse for it). The page shows the file name and size once it's staged.

Pick a service

Choose the ServiceUpstream the mocks bind to. Seeding targets an existing service — create the service first if you haven't. Seeded mocks land in that service's library exactly where recorded traffic would.

Pick a format

HAR, Postman v2.1, or OpenAPI 3.x. Auto-detected for JSON uploads; choose it yourself for YAML OpenAPI specs.

Commit

The dashboard POSTs to the seeding endpoint and renders the result — how many mocks were added, how many duplicates were dropped, any parser warnings, and a sample of the imported routes.

An Advanced options drawer exposes the per-format knobs (deduplication, and the OpenAPI-only 2xx only and prepend basePath toggles). The defaults match the API's server-side defaults, so committing without opening the drawer gives you the canonical run.

The seeding endpoint

The dashboard is a thin client over a single control-plane endpoint. Format is a path parameter so the URL is self-descriptive in logs:

POST /v1/seed/{format}?service_id=<id>&dedup=true
# format ∈ { har, postman, openapi }

The endpoint is authenticated like every other control-plane call — pass the X-API-Key header. The body can be sent three ways: a multipart file=field (the dashboard's drag-drop path), an application/json body with the parsed payload inline, or raw bytes (application/yaml / application/octet-stream) for a YAML or binary upload.

# Seed a service's library from a HAR export
curl -X POST 'http://localhost:8000/v1/seed/har?service_id=svc-payments' \
  -H "X-API-Key: $GHOST_API_KEY" \
  -F 'file=@session.har'

# Seed from an OpenAPI spec, keeping only 2xx responses
curl -X POST 'http://localhost:8000/v1/seed/openapi?service_id=svc-payments&success_only=true' \
  -H "X-API-Key: $GHOST_API_KEY" \
  -H 'Content-Type: application/yaml' \
  --data-binary @openapi.yaml

The response reports what was persisted: the count added, how many duplicates were dropped, parser warnings, and up to five sample routes:

{
  "format":      "har",
  "count":       42,
  "deduped":     5,
  "service_id":  "svc-payments",
  "warnings":    ["skipped 2 WebSocket frames (out of scope for HTTP mocking)"],
  "errors":      [],
  "sample_uris": ["GET /v1/charges", "POST /v1/charges", "GET /v1/customers/{id}"]
}

On the OSS proxy

The licensed product ships as Docker images and is driven through the dashboard or this control-plane API — there is no host CLI. The separate open-source proxy is a distinct product with its own CLI; if you're running that, it has its own seeding command. These docs describe the licensed product's API surface.

Per-format options

All three formats share service_id (required) and dedup. The rest are format-specific query knobs — passing a HAR-only knob to an OpenAPI import is simply ignored.

dedupAll formats

Default true. Drops a later row whose (method, URI, status, response body) hash matches an earlier one. Cross-format-safe, so importing a HAR and a Postman collection for the same endpoint in one session won't shadow each other with byte-identical mocks. Response headers and request body are deliberately excluded from the key — they jitter across exports.

methods / statusesHAR only

Comma-separated allow-lists. methods=GET,POST keeps only those verbs; statuses=200,201,204 keeps only those response codes. Everything else is dropped before persist.

environmentPostman only

A URL-encoded JSON object of { var: value } overlaid on top of the collection's own variables, so {{baseUrl}}-style placeholders resolve to concrete values.

success_onlyOpenAPI only

Skip non-2xx responses. Useful when a spec documents every error envelope but you only want the happy-path mocks.

prepend_basepathOpenAPI only

Prefix every imported URI with the path component of servers[0].url, for specs whose paths are relative to a base path the proxy will see on the wire.

What happens on import

Each parser normalises its input into the canonical mock row shape, the rows are deduplicated, persisted, and the proxy is signalled to reload:

Parse

The format parser walks the upload and emits mock rows (method, URI, request/response bodies, status, headers). URIs are normalised to a path-relative shape so they match regardless of which host the proxy is fronting. A single malformed entry never aborts the whole import — it's skipped with a warning so the rest still seeds.

Dedup

Unless dedup=false, byte-equivalent rows collapse to the first occurrence. Import order (HAR chronology, Postman walk order, OpenAPI path order) is preserved.

Persist

Rows are written to the durable Postgres mock library (the source of truth) tagged with source=seed_{format}, then mirrored to the on-disk replay library the proxy serves from.

Reload

The proxy is signalled to reload its library so the new mocks go live. The reload is best-effort — if it can't be reached, the import is not rolled back; the proxy reconciles on its next reload.

Once the import lands, switch the proxy to MOCK mode and the seeded mocks serve immediately through the same match cascade as recorded traffic — exact match first, AI generation only as a last resort, never on the request hot path.

Errors and warnings

The endpoint validates at the boundary and fails loudly. Two failure classes:

400

Bad request shape: an unsupported format in the path, a malformed multipart upload, or a malformed per-format query value (e.g. statuses that isn't a CSV of integers).

422

Unprocessable content: an unknown service_id for your tenant, an empty upload, or a payload the format parser rejects as structurally malformed.

Warnings are non-fatal and surface in the warnings array of a successful response — skipped WebSocket frames in a HAR (captured for observability, never replayed), an arbitrary oneOf branch chosen in an OpenAPI spec without a discriminator, an external $refthat wasn't chased, and the like. The import succeeds; the warnings tell you what was approximated or dropped.

A note on the data you import

Seeded mocks are subject to the same handling as recorded traffic. A floor of credential-bearing headers (Authorization, cookies, API keys, and the rest of the enterprise security-header set) is stripped before anything is written to disk. Bodies are kept verbatim on the local replay library so replay fidelity is exact, and PII in bodies is scrubbed when rows are written to the Postgres store and on any export.

Self-hosted, single-tenant

A HAR or Postman export can contain real production payloads. Everything you seed stays on your own host volume and Postgres — Gostly never sees your imported data. Each deployment is single-tenant, and seeded mocks bind to a service within that tenant. See the redaction reference for the header floor and body-scrub rules.

Next steps