Gateway route matchers
A common and annoying mismatch: the OpenAPI document describes the service’s own paths
(/users/{id}), but you actually have to call it through a gateway that mounts it somewhere
else (https://gw.example.com/api/v1/users/{id}).
Editing every URL by hand defeats the point of a live spec binding. A route matcher solves it by rewriting URLs at send time.
Import the gateway config
Section titled “Import the gateway config”Create a route matcher and paste the gateway’s own configuration. Three kinds are supported:
| Kind | What to paste |
|---|---|
kong | deck / declarative YAML |
nginx | nginx.conf |
envoy | Envoy YAML or JSON |
The config is stored inline in the matcher’s YAML under .tinspec/route-matchers/, so it is
committed with the project and reviewable.
Attach it
Section titled “Attach it”Two scopes:
- To an API provider — the usual case. In the provider’s settings, open the Network tab and pick the matcher, the upstream it corresponds to, and the gateway base URL. Every endpoint from that spec is then rewritten.
- To a single request — the request editor’s Gateway tab, for a one-off.
A request’s own binding wins over the provider’s.
A matcher applies wherever the request is sent from — directly from the editor, as a step in a
chain, as a single-node “test this step now”, as a request’s pre-run chain, and inside a pipeline.
All of them load the same matchers from .tinspec/route-matchers/, so a request cannot go to the
gateway one way and to the raw service URL another.
routeMatcher: matcher: edge-kong upstream: users-service gatewayUrl: "{{gatewayUrl}}"Leave upstream out and Tinspec matches automatically by comparing the spec’s server URL to
the routes’ upstreams. Put gatewayUrl in an environment so the
same project works against your local gateway and staging.
Check it before you rely on it
Section titled “Check it before you rely on it”The provider’s Network tab shows a live preview table: each spec path next to the gateway URL it will actually be sent to, with a running count (“38/41 endpoints rewritten”) and every unmatched endpoint flagged with the reason.
Read that table. An endpoint the gateway does not route is a real finding — either the route is missing or the spec documents something that is not exposed.
Manual overrides
Section titled “Manual overrides”When the config does not express a mapping — or expresses it in a way the parser cannot follow — add an explicit override:
overrides: - upstream: users-service from: /healthz # the backend path to: /api/v1/healthz # the gateway-facing pathThe common reason a route is unfollowable is a regex inbound match. Matching is done by inverting the gateway’s forward transform — given the backend path, produce the inbound path that would reach it — and a prefix or exact match inverts cleanly while an arbitrary regex does not. Simple regexes that are really prefixes in disguise are normalised; anything else is skipped, its endpoints show as unmatched, and an override is how you state the mapping by hand.
Send settings live on the same tab
Section titled “Send settings live on the same tab”The Network tab is also where a provider’s send settings go: timeout, redirect policy, TLS (client certificate, CA bundle, OS trust store), and the proxy for every request under that provider. “This whole API is behind the corporate proxy, with this client certificate” becomes one statement instead of a per-request chore.
They resolve in four layers, most specific first — the request’s own Settings tab, the collection or folder’s defaults, this API-provider layer, and the app’s global settings as the floor (timeout and redirects under Settings → Sending, proxy and TLS under Settings → Network). A field this layer does not set is not “default”: it shows the value that will apply and where it comes from — “30 s — from provider billing-staging” — computed by the engine that does the sending rather than re-derived in the UI.
Proxy and TLS are deliberately offered on a folder, a provider and global settings, but not on
an individual request: they describe a network, not a call. Secret material stays a reference —
tls.clientKeyRef, proxy.auth.passwordRef — so a committed file never carries the value.
gRPC to REST transcoding
Section titled “gRPC to REST transcoding”A gateway can also transcode gRPC to JSON — Envoy’s grpc_json_transcoder being the common
case. Mark the matcher as transcoding; for Envoy configs this is auto-detected and the toggle
just reflects it.
Then a unary gRPC method carrying a google.api.http annotation is sent as the mapped
HTTP call rather than as native gRPC. The gRPC editor shows a chip naming the path it will
use, so the decision is visible rather than surprising.
Streaming methods and methods without the annotation fall back to native gRPC.
Limits at v0.1.0-preview.10
Section titled “Limits at v0.1.0-preview.10”- The provider preview table shows the native gRPC retarget for a transcoding matcher — transcoded preview rows are not rendered. Transcoding needs the compiled descriptors, which the send path has and the preview does not.
- The provider and collection send-settings layers do not apply inside a chain. A chain run
is given your auth providers and your route matchers, but not the settings layers, so only a
request’s own
settingsblock applies. A suite behind a provider-configured proxy therefore works in the editor and fails in a chain. Put the setting on the request itself until this is wired. - There is no gRPC settings editor. Message-size limits and compression are carried in the file format and resolved by the engine, but nothing in the app edits them yet.
- A proxy is not applied to gRPC. Rather than silently bypassing it, the engine refuses the
send and names the proxy and the layer that configured it, so the fix — a
noProxyentry for that host, or clearing the proxy for that request — is obvious.
In the file format
Section titled “In the file format”routeMatchers: - name: edge-kong kind: kong config: | services: - name: users-service url: http://users:8000 routes: - name: users paths: [/api/v1] strip_path: true overrides: - upstream: users-service from: /healthz to: /api/v1/healthz transcodes: false