Running wiretap against multiple OpenAPI specs

Validate traffic against many OpenAPI contracts at once.

One proxy, many contracts

wiretap can load many OpenAPI specifications at the same time and route each incoming request to the contract that owns it. We call this multi-spec mode.

Real systems are rarely described by a single OpenAPI contract. Services each ship their own spec, API gateways stitch together specs from multiple backends/polyrepos, and monorepos collect dozens of contracts in one tree.

multi-spec mode lets wiretap validate traffic across all of them, without having to merge or pre-process the contracts first.

This is much more typical of real-world, multi-service application deployment.

To enable it, point wiretap at more than one spec using --specs, or hand it a directory to scan with --spec-dir.

wiretap --specs ./users.yaml,./orders.yaml,./billing.yaml -u https://api.pb33f.io

Let wiretap discover all the service OpenAPI contracts automatically, just point it at a directory.

wiretap --spec-dir ./contracts -u https://api.pb33f.io

How it works

When wiretap boots in multi-spec mode, it does three things:

  • Discovers every spec from the supplied flags, directories, and globs.
  • Analyzes the loaded contracts for conflicts and prints a report.
  • Routes each live request through the ordered spec resolver.

Discovery

wiretap accepts explicit paths, globs, directories, and remote URLs.

Directory and glob discovery picks up files if they have a .yaml, .yml, or .json extension and contain an OpenAPI marker (openapi:, "openapi", swagger:, or "swagger"). Explicit paths and remote URLs are loaded as provided, and any invalid contract is reported as a load error.

Anything else in the directory is ignored, so you can drop wiretap on top of an existing repo without curating the layout.

Discovery preserves order: specs supplied through --spec and --specs come first, including globs and remote URLs. Directory matches follow. Directory and glob matches are walked in lexical path order. The first discovered spec becomes the primary contract unless you set --spec or contract in wiretap.yaml. CLI values take priority when both are supplied. The primary contract is the one returned to the monitor UI for schema previews and references.

wiretap’s monitor UI still only supports a single contract, this will be upgraded soon to show all the contracts. It is important to know that this has no effect on wiretap’s operation, it’s just the UI only renders a single spec at the moment.

To skip files or folders, use --ignore with one or more glob patterns:

wiretap --spec-dir ./contracts --ignore '**/legacy/**' --ignore '**/*-draft.yaml' -u https://api.pb33f.io

Routing

For every inbound request, wiretap walks the loaded contracts in discovery order.

Inside a single spec, matching is specificity-first: literal segments (/users/me) score higher than templated segments (/users/{id}). Across specs, discovery order is the tiebreak. The first spec with a matching path and method wins. If earlier specs only match the path, wiretap keeps walking so a later path-and-method match can still win.

If no spec matches both path and method, wiretap falls back to the first spec that matched the path. If no spec covers the path, it falls back to the first spec so you still get a clean path not found validation error instead of a silent passthrough. Resolved routes are cached so repeat traffic skips the walk.

Operation-level and path-level servers: blocks are honored. If a spec defines /v2 as a server base path, requests to /v2/users are routed to that spec and the base path is stripped before validation.


Conflict analysis

Loading multiple specs at once means routes might overlap. wiretap detects multiple kinds of conflict at startup and prints a report:

Conflict Meaning
cross-spec-duplicate Two specs define the exact same route on the same method
cross-spec-ambiguous Two specs define routes on the same method that could match the same request
within-spec-duplicate A single spec defines the same route twice (after server base paths are applied)
within-spec-ambiguous A single spec defines two routes that could match the same request
duplicate-operation-id Two operations share the same operationId

Ambiguity is detected with type awareness. /users/{id} typed as integer does not collide with /users/me, because me cannot satisfy integer. string parameters overlap anything, and integer overlaps number.

When a request hits a conflicting route at runtime, the matched transaction is tagged with a spec conflict marker and surfaced in the monitor UI with a warning banner showing which specs cover the same route.

This makes ambiguous traffic visible during interactive debugging, not just at startup.

Ignoring operationId conflicts

Duplicate operationId values across specs are flagged by default. If your contracts intentionally re-use ids (common when versioning specs side-by-side), suppress them with --ignore-clashing-operationid:

wiretap --spec-dir ./contracts --ignore-clashing-operationid -u https://api.pb33f.io

Dry run

The --dry-run flag tells wiretap to discover, analyze, and report — then exit. No HTTP server is started, no traffic is proxied. It’s the fastest way to check that a set of contracts is loadable and conflict-free.

wiretap --spec-dir ./contracts --dry-run

A dry run exits with status code 0 when all specs load and no conflicts are found, and non-zero when conflicts or load errors are detected.

The same report you see in multi-spec mode at startup is produced by --dry-run, including load errors with the file and reason.

Dry run is also useful locally when adding a new spec to an existing tree. Run it once, see the diff in the report, decide whether the new conflicts are intentional.

Combine --dry-run with --ignore-clashing-operationid if your CI gate cares about routes but not ids.


Configuration file

Every flag has a wiretap.yaml equivalent.

contracts:
  - ./users.yaml
  - ./orders.yaml
contractDirs:
  - ./contracts
contractIgnore:
  - "**/legacy/**"
  - "**/*-draft.yaml"
contract: ./users.yaml          # primary spec (optional)
ignoreClashingOperationId: true
dryRun: false
Property Type Description
contracts []string Explicit list of OpenAPI specs to load
contractDirs []string Directories to recursively scan for specs
contractIgnore []string Glob patterns to exclude during discovery
contract string Path to the primary spec (used by the monitor UI)
ignoreClashingOperationId boolean Suppress duplicate-operation-id conflicts
dryRun boolean Run discovery and analysis, then exit

In single-spec setups, --spec works exactly as it always has — multi-spec mode activates automatically when more than one spec is loaded.