Problem 1
A forgotten route stays open
The gateway and the contract drift apart; a route nobody knows still answers.
Flexway's answer: Only what the contract declares is served: an undeclared route answers 404 in problem+json.
API
One OpenAPI 3.1 is enough: Flexway serves exactly what it declares, validates requests against the schema and relays to your services, over REST, gRPC, SSE or WebSocket.
12 of the 13 shown delivered · since v0.1.0
What you expect from this domain


Problem 1
The gateway and the contract drift apart; a route nobody knows still answers.
Flexway's answer: Only what the contract declares is served: an undeclared route answers 404 in problem+json.
Problem 2
A typo is found at deploy time, under traffic.
Flexway's answer: flexway validate refuses the configuration offline, in CI; an invalid configuration never replaces the running one.
Problem 3
Rewriting hundreds of routes of an existing gateway blocks every change.
Flexway's answer: Importing an existing gateway's configuration produces the configuration and a coverage report.
Every step is a decision readable in the trace and in the console.
API - Domain diagram: who calls, the decision steps, what is called, and where a request is refused.
not declared: 404
The applications that call your APIs: each request goes through Flexway, which checks the contract and the identity before reaching your systems.
Routes through here
Browsers: REST calls and real-time streams (SSE, WebSocket), relayed by Flexway without buffering.
Routes through here
The partner companies that consume your APIs: identified by a client certificate or an API key, under a quota per tenant.
Routes through here
Flexway serves only what your OpenAPI, AsyncAPI or Protobuf contract declares; anything else gets a 404 without reaching your services.
Routes through here
Flexway checks who is calling (OIDC token, API key or client certificate) and reads the tenant from the identity; no valid identity: 401.
Routes through here
Parameters and body are validated against the contract's schema; a non-conforming request gets 422 without reaching the upstream.
Routes through here
The route's policies: contract schema, transformations, cache isolated per tenant, a call to a decision service that may refuse.
Routes through here
Flexway relays to the upstream without buffering, under a bounded deadline and a circuit breaker; each decision leaves an OpenTelemetry trace.
Routes through here
Your HTTP services: Flexway relays the declared operations to them, over HTTP/1.1 or HTTP/2.
Routes through here
Your gRPC services: served over gRPC, gRPC-Web and REST translated by Protobuf descriptors.
Routes through here
Your services' SSE and WebSocket streams, relayed by Flexway without buffering.
Routes through here
The essentials of each topic, with its status in the published release; unfold a card for the full text.
Flexway serves exactly the operations of the OpenAPI contract: an undeclared route answers 404, and an operation without an upstream prevents start-up.
Flexway loads an OpenAPI 3.1 contract and derives the set of served routes from it: exactly the declared operations, nothing more and nothing less. A route missing from the contract answers 404 by construction, with no rule to write to close it. A declared operation with no upstream prevents start-up: the gateway refuses to serve a partial configuration.
The flexway.yaml file describes how to serve - hosts, upstreams, issuers, policies - and lists no operation. Anything specific to an operation lives in the contract, as extensions reviewed alongside it by the team that changes it: x-flexway-upstream, x-flexway-timeout, x-flexway-rate-class, x-flexway-cache, x-flexway-tool. A host can serve its own contracts (hosts.<host>.contracts); the same route twice on one host, an operationId present in two contracts or an operation relayed to two upstreams are refused at load.
Decoding is strict: an unknown key is refused, never ignored, and every problem is reported in one pass. When taking over an existing API, the 404 on undeclared operations often reveals routes the previous gateway exposed without the contract ever mentioning them.
flexway validate checks the configuration offline, in CI, and hot reload never replaces the running configuration with an invalid one.
flexway validate checks, with no cluster and no network, that the file matches its schema, that the contracts load, that every operation has an upstream and that no upstream is orphaned. It exits non-zero on error, which makes it a CI step, and prints config_digest: the semantic fingerprint of what it loaded, identical whatever the mount path. That is the value a CI job can expect to see served after a merge.
Reloading goes through an immutable snapshot: the content fingerprint is re-read every server.reload.interval (5 s by default) and on SIGHUP. One hundred reloads under load lost no request, in-flight streams included, and unchanged upstreams and issuers are reused. An invalid configuration never replaces the running one: the refusal is logged once per version, counted (flexway.config.reloads) and visible in last_reload under /config.
Secrets are written as references only, ${VAR} or file:/path; a plain value under a secret key refuses the load. A few settings cannot be reloaded (server.shutdown, observability, server.reload, server.in_flight, server.cache): changing them refuses the reload as a whole, naming the key.
A one-off, offline import of an existing gateway's configuration produces a validated flexway.yaml and a report of what is taken over or has no equivalent.
Importing an existing gateway's configuration is a one-off, offline import, never something read at start-up. Each endpoint is matched to a contract operation by method and path template; an endpoint absent from the contract is listed, never invented. The generated flexway.yaml goes through the real loader before it is written: what comes out of the import starts.
The output, in an empty directory, holds the configuration, the annotated contract with the same patch as JSON Patch (RFC 6902), and a coverage report that classifies each item: taken over, taken over differently, no equivalent. Upstreams, timeouts, rate limits and circuit breakers land in upstreams, x-flexway-timeout and policies; a contract less strict than the old configuration is reported, never silently changed. Embedded scripts and native plugins have no equivalent: no third-party code runs in the process.
SSE streams, WebSocket, gRPC and gRPC-Web are relayed end to end, and a gRPC upstream becomes callable over REST from its google.api.http annotations.
SSE responses and chunked bodies are relayed without buffering: each chunk leaves as soon as it arrives. A stream is governed only by the inactivity timeout between two bytes (server.timeouts.read), never by the total exchange timeout. WebSocket is relayed after identity and rate checks at opening, and the connection outlives the total budget. On shutdown, /readyz turns red and in-flight streams are drained within a declared bound (server.shutdown.drain).
A gRPC upstream described by its Protobuf descriptors (contracts.protobuf) becomes callable over REST: the mapping comes from google.api.http annotations, the response comes back as canonical proto3 JSON, and a server stream becomes a text/event-stream, one message per event. gRPC and gRPC-Web are also served end to end, over h2c or TLS on the traffic listener, with no second port. An error on the gRPC surface is a google.rpc.Status whose ErrorInfo.reason carries the problem code.
Mappings the translation cannot honour (multi-segment variables, wildcard segments, verbs, client or bidirectional streaming over REST) are refused at load rather than served approximately. HTTP/3 on the caller side is upcoming.
The rest-minimal example, as it ships with Flexway v1.6.3.
# The smallest useful configuration: one contract, one upstream. Every operation of the contract is
# served and relayed there; nothing else is.
version: 1
contracts:
openapi: ./openapi.yaml
upstreams:
default:
url: http://orders.internal:8080openapi: 3.1.0
info:
title: Orders
version: "1.0.0"
# The team that answers for every operation of this contract - the console's catalogue shows it
#; an operation may name its own.
x-flexway-owner: { team: orders-team, contact: "#orders" }
paths:
/orders:
get:
operationId: listOrders
parameters:
- { name: status, in: query, schema: { type: string, enum: [open, closed] } }
responses: { "200": { description: The orders } }
post:
operationId: createOrder
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [sku, quantity]
properties:
sku: { type: string }
quantity: { type: integer, minimum: 1 }
responses: { "201": { description: Created } }
/orders/{id}:
get:
operationId: getOrder
parameters: [ { name: id, in: path, required: true, schema: { type: string } } ]
responses: { "200": { description: One order } }What is delivered in the published release v1.6.3, and what is coming; a feature is never shown as delivered before its release.
| Feature | Status |
|---|---|
| An OpenAPI 3.1 contract loaded; what is served is derived from it | Delivered · v0.1.0 |
| flexway validate offline, output usable in CI | Delivered · v0.1.0 |
| Live reload through an immutable snapshot, no request lost | Delivered · v0.1.0 |
| Import of an existing gateway's configuration, with a coverage report | Delivered · v1.1.0 |
| Streams relayed without holding: SSE and chunked bodies | Delivered · v0.1.0 |
| WebSocket relayed | Delivered · v0.1.0 |
| REST to gRPC translation through Protobuf descriptors | Delivered · v0.2.0 |
| gRPC and gRPC-Web end to end | Delivered · v0.2.0 |
| HTTP/3 on the caller side | Planned |
| Effective policy chain per route | Delivered · v0.1.0 |
| An invalid configuration never replaces the running one | Delivered · v0.1.0 |
| Declarative proposal: a diff, never a mutation | Delivered · v1.2.0 |
| Pull request opened from the proposal | Delivered · v1.2.0 |
The other expectations of this domain
Flexwiz is a young company: you talk directly with the person who founds it. Tell us what you want to run through Flexway. We talk about your infrastructure and your digital sovereignty requirements.
Online booking is coming soon; until then, an e-mail is enough.