flexway
FRENTalk to an expert

API

The contract is the configuration.

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

  • API gateway in front of React, Next.js, mobile, microservicesDelivered · since v0.1.0
  • Several API styles behind one entry pointDelivered · since v1.1.0
  • Distinct policies for public, partner and internal APIsDelivered · since v0.1.0
Every market expectation
Catalogue, an open operationCatalogue, an open operation
The catalogue reads the contract: the operation's owner, hosts, deadline budget and security alternatives come from the file.Real console capture, demo data · v1.6.3

What it solves

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.

Problem 2

A broken configuration reaches production

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

Migrating costs too much

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.

How it works

Every step is a decision readable in the trace and in the console.

Your infrastructureflexwayAPI, AI and agent gatewayUnified Decision Chain (UDC)404not declared: 40401 Contract02 Identity03 Schema04 Policies05 RelayApplicationsBrowsersPartnersHTTP servicesgRPC servicesSSE, WebSocket streamsYour infrastructureflexwayAPI, AI and agent gatewayUnified Decision Chain (UDC)40401 Contractthe operation is declared, otherwise 40402 Identitytoken, key or certificate03 Schemaparameters and body validated, after the quotas04 Policiestransformations, external call, cache05 RelayHTTP, gRPC, SSE, WebSocket, no buffering; one trace per decisionApplicationsBrowsersPartnersHTTP servicesgRPC servicesSSE, WebSocket streams

API - Domain diagram: who calls, the decision steps, what is called, and where a request is refused.

  • Applications
  • Browsers
  • Partners
  1. Contract
  2. Identity
  3. Schema
  4. Policies
  5. Relay
  • HTTP services
  • gRPC services
  • SSE, WebSocket streams

not declared: 404

Applications
The applications that call your APIs: each request goes through Flexway, which checks the contract and the identity before reaching your systems.
Browsers
Browsers: REST calls and real-time streams (SSE, WebSocket), relayed by Flexway without buffering.
Partners
The partner companies that consume your APIs: identified by a client certificate or an API key, under a quota per tenant.
Contract
Flexway serves only what your OpenAPI, AsyncAPI or Protobuf contract declares; anything else gets a 404 without reaching your services.
Identity
Flexway checks who is calling (OIDC token, API key or client certificate) and reads the tenant from the identity; no valid identity: 401.
Schema
Parameters and body are validated against the contract's schema; a non-conforming request gets 422 without reaching the upstream.
Policies
The route's policies: contract schema, transformations, cache isolated per tenant, a call to a decision service that may refuse.
Relay
Flexway relays to the upstream without buffering, under a bounded deadline and a circuit breaker; each decision leaves an OpenTelemetry trace.
HTTP services
Your HTTP services: Flexway relays the declared operations to them, over HTTP/1.1 or HTTP/2.
gRPC services
Your gRPC services: served over gRPC, gRPC-Web and REST translated by Protobuf descriptors.
SSE, WebSocket streams
Your services' SSE and WebSocket streams, relayed by Flexway without buffering.
  • Line: one route
  • Interchange: shared decision
  • Request
  • Refusal
  • Your infrastructure
  1. Contractthe operation is declared, otherwise 404
  2. Identitytoken, key or certificate
  3. Schemaparameters and body validated, after the quotas
  4. Policiestransformations, external call, cache
  5. RelayHTTP, gRPC, SSE, WebSocket, no buffering; one trace per decision

In detail

The essentials of each topic, with its status in the published release; unfold a card for the full text.

Served = declared: the contract decides every route

Delivered · v0.1.0

Flexway serves exactly the operations of the OpenAPI contract: an undeclared route answers 404, and an operation without an upstream prevents start-up.

  • Served routes = contract operations, zero tolerated drift
  • Operation without an upstream: start-up refused
  • Unknown key refused, all errors in one pass
See the detailHide the detail - Served = declared: the contract decides every route

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.

All the points

  • Served routes = contract operations, zero tolerated drift
  • Operation without an upstream: start-up refused
  • Per-operation settings as x-flexway-* extensions
  • Unknown key refused, all errors in one pass

Features and status

  • An OpenAPI 3.1 contract loaded; what is served is derived from itDelivered · v0.1.0
  • Start refused when a declared operation has no upstreamDelivered · v0.1.0
  • x-flexway-* extensions read in the contract, never anywhere elseDelivered · v0.1.0
  • flexway.yaml: hosts, upstreams, contract references - no operationDelivered · v0.1.0
  • Several contracts and hosts, conflicts detected at load timeDelivered · v0.1.0
Read in the documentation : Serving your first API

Validate offline, reload without dropping traffic

Delivered · v0.1.0

flexway validate checks the configuration offline, in CI, and hot reload never replaces the running configuration with an invalid one.

  • flexway validate: offline, CI-friendly exit code
  • Hot reload with no lost request
  • Secrets by reference only
See the detailHide the detail - Validate offline, reload without dropping traffic

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.

All the points

  • flexway validate: offline, CI-friendly exit code
  • config_digest to check what is actually served
  • Hot reload with no lost request
  • Secrets by reference only

Features and status

  • flexway validate offline, output usable in CIDelivered · v0.1.0
  • Live reload through an immutable snapshot, no request lostDelivered · v0.1.0
  • An invalid configuration never replaces the running oneDelivered · v0.1.0
  • Secret references resolved at run time, never a plain valueDelivered · v0.1.0
Read in the documentation : Changing the configuration without a restart

Importing an existing gateway's configuration

Delivered · v1.1.0

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.

  • Offline import, result validated before writing
  • Coverage report: taken over, taken over differently, no equivalent
  • No silent translation
See the detailHide the detail - Importing an existing gateway's configuration

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.

All the points

  • Offline import, result validated before writing
  • Coverage report: taken over, taken over differently, no equivalent
  • Distinct exit codes: all taken over (0), gaps (3), refused with nothing written (1)
  • No silent translation

Features and status

  • Import of an existing gateway's configuration, with a coverage reportDelivered · v1.1.0
Read in the documentation : Take over an existing gateway

Streams, WebSocket and gRPC end to end

In part

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 and chunked bodies relayed unbuffered
  • WebSocket: identity and rate checked at opening
  • REST to gRPC from google.api.http, server streams as SSE
See the detailHide the detail - Streams, WebSocket and gRPC end to end

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.

All the points

  • SSE and chunked bodies relayed unbuffered
  • WebSocket: identity and rate checked at opening
  • REST to gRPC from google.api.http, server streams as SSE
  • gRPC and gRPC-Web on the same listener
  • Caller-side HTTP/3: planned

Features and status

  • Streams relayed without holding: SSE and chunked bodiesDelivered · v0.1.0
  • WebSocket relayedDelivered · v0.1.0
  • REST to gRPC translation through Protobuf descriptorsDelivered · v0.2.0
  • gRPC and gRPC-Web end to endDelivered · v0.2.0
  • Graceful shutdown: streams in flight are drainedDelivered · v0.1.0
  • HTTP/3 on the caller sidePlanned
Read in the documentation : A gRPC upstream

Configuration

The rest-minimal example, as it ships with Flexway v1.6.3.

examples/rest-minimal/flexway.yaml
# 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:8080
examples/rest-minimal/openapi.yaml
openapi: 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 } }

Features

What is delivered in the published release v1.6.3, and what is coming; a feature is never shown as delivered before its release.

FeatureStatus
An OpenAPI 3.1 contract loaded; what is served is derived from itDelivered · v0.1.0
flexway validate offline, output usable in CIDelivered · v0.1.0
Live reload through an immutable snapshot, no request lostDelivered · v0.1.0
Import of an existing gateway's configuration, with a coverage reportDelivered · v1.1.0
Streams relayed without holding: SSE and chunked bodiesDelivered · v0.1.0
WebSocket relayedDelivered · v0.1.0
REST to gRPC translation through Protobuf descriptorsDelivered · v0.2.0
gRPC and gRPC-Web end to endDelivered · v0.2.0
HTTP/3 on the caller sidePlanned
Effective policy chain per routeDelivered · v0.1.0
An invalid configuration never replaces the running oneDelivered · v0.1.0
Declarative proposal: a diff, never a mutationDelivered · v1.2.0
Pull request opened from the proposalDelivered · v1.2.0

Every feature

The other expectations of this domain

  • Work offline, bufferNo central plane on the path: a local gateway decides with no network; buffering stays with the local broker; edge mode plannedPartly · next in 1.11
  • Distributed clinical gatewayMQTT proxy planned, edge mode plannedPartly · next in 1.7
  • 2028-2030 "optimise": federated policies, dynamic selection, arbitration of cost, performance, riskFederation: candidate; arbitration by declared rules onlyTo be scheduled
  • Edge, cloud and device cooperation; central policies applied locallyThe binary runs locally with no central plane; signed configuration pulled by a site: plannedPlanned in 1.11
  • GraphQL: limit query complexityProposed decision: declared persisted queries, whose cost is judged at registrationTo be scheduled

The other domains

Let's talk about your gateway

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.