API_CLIENT_RUNNER_ARTIFACT_KIND/API_CLIENT_RUNNER_ARTIFACT_VERSIONplusexportApiClientRunnerArtifact,parseApiClientRunnerArtifactandserializeApiClientRunnerArtifactremain public package-root APIs for the versioned, history-free artifacts used by the Runner UI.apiClientCollectionRunName,apiClientCollectionRunRequestsandrunApiClientCollectionremain the canonical runner helpers and preserve saved-request ordering.ApiClientCodeEditor,ApiClientScriptEditorandApiClientHistoryPageremain exported from@prauga/flexdoc-clientfor applications that need lower-level product surfaces.
Using FlexDoc
FlexDoc is a backend-aware API workbench. Start by connecting it to your backend, then compare the running route surface with OpenAPI, investigate findings, and reproduce requests.
Getting started
For a React renderer, install the current client package and stylesheet. The package version comes from the release feed, not from a product-milestone number:
npm install @prauga/flexdoc-clientFor the disagreement loop, start with Express, Spring MVC, or ASP.NET Core. Native packages keep their own versions.
Open the framework install selector →
Architecture
FlexDoc has one canonical browser renderer and one canonical API Client request model. Framework adapters own the OpenAPI document, local renderer assets and backend-only capabilities; they do not reimplement the UI per language.
browser renderer / API Client
│
├── direct browser transport
│
└── advertised host transport
POST <docsPath>/__flexdoc/execute
X-FlexDoc-Execute: 1Host execution changes the network transport of the resolved request. Request editing, variables, auth inheritance, scripts, tests, History, collection ordering and response views remain shared.
This is the product boundary that comes from FlexDoc being installed inside the backend: a supported adapter can deliberately expose controlled execution from the service/network context without creating a separate Java, Go, Python, Rust, Ruby, Elixir, PHP or .NET API client.
API workbench
Findings, Try It, and saved requests use the same request workspace. The renderer supports OpenAPI 3.0.x/3.1.x, references, server variables, composed/recursive schemas, parameter serialization, generated request samples, Viewer Settings and light/dark/high-contrast appearance.
Try It and the API Client share the same request editor. The workspace adds collections, nested folders, variables/environments, inherited auth, scripts/tests, searchable History, Postman Collection v2.1/environment import, collection/folder runs and portable Runner artifact export.
Request bodies include JSON, raw text, URL-encoded, multipart/form-data, binary and GraphQL modes. Pretty/Raw/Preview, response search, header inspection and copy-as-cURL consume the same normalized response regardless of direct or host transport.
Host execution
Host execution is off by default on the server. When a serving adapter explicitly enables a real executor and advertises hostExecution.available: true, ordinary interactive API Client sends prefer the API host by default.
This remains true for capabilities: []. An empty list means basic native host transport is available but no advanced host-only capabilities are advertised; it does not mean the client should fall back to browser fetch for every ordinary request.
Reusable collection/headless execution deliberately stays direct by default unless the caller explicitly opts into host semantics or the request requires a host-only capability. Requests requiring unsupported capabilities fail closed.
setupFlexDoc(app, '/docs', {
spec,
options: {
tryIt: {
hostExecution: {
allowedOrigins: ['https://api.internal.example'],
// preferHostExecution: false, // optional Node routing preference
},
},
},
});On the Node backend, hostExecution: true also enables the executor and can derive exact origins from OpenAPI servers. For production, prefer an explicit allowlist whenever the intended execution surface is narrower than the specification.
# Spring Boot example
flexdoc:
try-it-host-execution: true
try-it-host-execution-allowed-origins:
- https://api.example.com
- https://staging-api.example.comX-FlexDoc-Execute: 1 is protocol/cross-site friction only. It is not authentication and is not a CSRF token.Host capability matrix
An adapter advertises host execution only when a real execute binding is attached. Most native executors advertise capabilities: [], which means basic host transport. Node retains the richer host-only capability set.
| Adapter / framework | Execute route | Advertised host-only capability level |
|---|---|---|
| Node — Express / Fastify / Hono / Nest | Yes | cookies, client certificates, Digest, Hawk, OAuth 1.0, AWS SigV4 |
| Java — Spring Boot | Yes | basic host transport; capabilities: [] |
| Java — JAX-RS | Yes | basic host transport; capabilities: [] |
| Python — FastAPI / ASGI | Yes | basic host transport; capabilities: [] |
| Go | Yes | basic host transport; capabilities: [] |
| ASP.NET Core | Yes | basic host transport; capabilities: [] |
| Rust — Axum | Yes | basic host transport; capabilities: [] |
| Rust — Actix Web | Yes | basic host transport; capabilities: [] |
| Ruby — Rack / Rails | Yes | basic host transport; capabilities: [] |
| Elixir — Plug / Phoenix | Yes | basic host transport; capabilities: [] |
| PHP — Laravel / Symfony | Yes | basic host transport; capabilities: [] |
| Python — Flask / Django / WSGI | No | renderer-only |
Framework-neutral JVM hosting can be reused by other Java/Kotlin integrations, but an integration must own and protect the execute route before it may advertise available: true.
Bearer, Basic, OAuth 2.0 access tokens and header/query API keys do not require an advanced host-only capability. Cookie API keys require cookie-capable host execution. NTLM intent is preserved in the request model but no current executor advertises NTLM support.
Security model
allowedOrigins is an exact HTTP(S) origin boundary. Private RFC1918/VPC destinations are allowed only when the operator explicitly allowlists the exact origin; link-local and cloud-metadata destinations remain blocked.
Native hardened transports validate the address set and pin the actual connection to validated addresses while retaining the original hostname for HTTP authority, SNI and TLS certificate verification. They revalidate redirect hops and avoid implicit/system proxy routing so a proxy cannot silently bypass destination policy.
- cross-origin redirects are rejected, even if the second origin is allowlisted;
- unsafe transport/browser headers and CR/LF-bearing values are rejected or stripped;
- native execute envelopes are bounded to 32 MiB and returned response bodies to 10 MiB;
- redirects are bounded to five hops and execution timeouts remain clamped;
- server-only Node client certificates and interceptors are never serialized into the browser page.
Operations
Host execution turns an interactive request into browser → API host → target API traffic. Treat that as real CPU, memory, socket, DNS/TLS, bandwidth and target-service load.
FlexDoc's transport safety policy is not a per-user abuse policy. Production deployments should apply caller-aware rate limiting, bound concurrent execute requests, reject overload before unbounded queueing, and monitor execute traffic separately from ordinary documentation requests.
const admission = createHostExecutionAdmission({ maxInFlight: 16 });
app.use('/docs', requireDocumentationUser);
app.use('/docs/__flexdoc/execute', requireSameOriginOrCsrfToken);
app.use(
'/docs/__flexdoc/execute',
createHostExecutionAdmissionMiddleware(admission, { retryAfterSeconds: 1 }),
);The Spring starter similarly exports FlexDocHostExecutionAdmissionFilter; 16 concurrent execute requests per process is the shipped reference starting point, with HTTP 429 and Retry-After: 1 on saturation.
The shared JVM executor has fixed last-resort ceilings of 64 transport workers, 256 queued executions, 256 total Apache connections and 256 connections per route. Those are resource-safety ceilings, not recommended application concurrency.
For multi-replica deployments, user/session quotas belong in a shared gateway or distributed limiter. Useful signals include accepted/rejected requests, in-flight count, p95/p99 duration, timeout/DNS/policy/upstream errors, body sizes, outbound connections/egress, CPU and RSS/PSS.
Automation
Export one saved request, folder subtree, or collection with its selected environment as a versioned history-free artifact and execute it locally or in CI.
npx @prauga/flexdoc-cli validate http://127.0.0.1:3000/docs/__flexdoc/runtimeflexdoc validate exits 1 when the status is fail. Warnings and informational acknowledgements do not fail the command unless you pass --fail-on warning or --fail-on info.
flexdoc run ./pets.flexdoc.json --report ./flexdoc-report.jsonThe Runner reuses canonical request ordering, variable mutations, inherited auth, pre-request scripts and response tests. HTTP 4xx/5xx alone is not a Runner failure; transport/build errors, script errors and failed flex.test assertions are.
--host consumes an existing advertised host-execution contract; it does not invent a second execute endpoint. Reusable/headless execution remains direct by default unless host semantics are selected or required.
--header, --bearer and --basic authenticate the FlexDoc docs/host endpoint only and are never copied to a direct target API request.Contract Validation
Node (Express, Fastify, Hono, NestJS), Spring MVC, and ASP.NET Core produce operation-level findings from runtime discovery and OpenAPI. The renderer and flexdoc validate consume that backend-owned result. FastAPI, Flask, and Django can show a route snapshot and do not emit this validation object.
Findings distinguish undocumented routes, documented routes that were not observed, method mismatches, and verified duplicate registrations. Partial discovery stays explicit. Read how runtime and OpenAPI are compared →
Acknowledging intentional routes
Acknowledgement is a disposition. The route stays in the runtime record, the finding stays at info severity, and the check does not fail. It is not a way to hide the route from Runtime Intelligence.
Runtime Intelligence
Runtime Intelligence remains opt-in and observational. Because FlexDoc is installed inside the backend, supported adapters can inspect the application's actual route inventory and compare it with the documented contract.
Contract validation is produced by Node (Express, Fastify, Hono, NestJS), Spring MVC, and ASP.NET Core. FastAPI, Flask, and Django can show a route snapshot. Other adapters serve the renderer and do not invent a route inventory. Incomplete discovery is marked incomplete instead of guessed.
Framework adapters
FlexDoc serves the same renderer from Node, .NET, JVM, Python, PHP, Ruby, Go, Rust and Elixir integrations. Renderer support, Runtime Intelligence, Contract Validation and host execution are separate capability axes; installing a renderer adapter does not imply that every backend-only feature is available.
Spring, JAX-RS, ASP.NET Core, and the other native host executors require application-owned authentication around the execute route. Origin allowlisting does not identify the caller.
Current package versions
| Ecosystem | Artifact | Published version |
|---|---|---|
| npm | @prauga/flexdoc-client | 3.5.0 |
| npm | @prauga/flexdoc-backend | 3.5.0 |
| npm | @prauga/flexdoc-core | 0.5.2 |
| npm | @prauga/flexdoc-cli | 0.8.0 |
| NuGet | Prauga.FlexDoc.AspNetCore | 0.8.0 |
| Maven | flexdoc-jvm / flexdoc-jaxrs / flexdoc-spring-boot-starter | 0.11.0 |
| PyPI | prauga-flexdoc | 0.9.0 |
| Composer | prauga/flexdoc | 0.5.0 |
| RubyGems | prauga-flexdoc | 0.5.0 |
| crates.io | prauga-flexdoc-host-execution | 0.2.0 |
| crates.io | prauga-flexdoc-axum | 0.6.0 |
| crates.io | prauga-flexdoc-actix | 0.5.0 |
| Hex | prauga_flexdoc | 0.5.0 |
| Go | github.com/prauga/flexdoc/adapters/go | 0.6.0 |
Native adapters keep independent versions. FlexDoc 3.5.0 is the JavaScript product release. Java 0.11.0 and ASP.NET Core 0.8.0 carry the same disagreement loop. The table is the current published set, not one shared version number.
Performance & Host Impact
The docs-host baseline measures documentation generation, bundle size, startup, and memory. A separate host-impact workflow compares matched direct and host-active traffic.
The baseline tracks latency, throughput, CPU/request, RSS/PSS and cooldown retention so the cost of running execution inside the service remains visible. Managed-runtime PSS is treated as directional investigation context rather than proof of live-object retention.
Current source APIs & boundaries
The client, CLI, and adapters keep one request model. Host transport is used only when the backend serving FlexDoc advertises it.
- One API Client state and request model is shared by findings, Try It, and saved requests.
hostExecution.available: trueadvertises a working adapter-owned execute endpoint. Interactive sends prefer that transport by default, including hosts that advertisecapabilities: []. - An empty capability list means basic host transport exists, not that host execution is unavailable. Cookie jars, client certificates, Digest, Hawk, OAuth 1.0 and SigV4 remain capability-gated and fail closed when a host does not advertise them.
- Reusable collection/headless execution keeps direct transport as its default unless host semantics are selected or required. Native adapters must own a real execute binding before they advertise
available: true.
- Runner scripts execute in the CLI process. Variable resolution, pre-request scripts, inherited auth, transport, response tests and collection/environment mutations keep the workspace ordering even when transport is delegated to an advertised host executor.
--hostloads the existing host-execution advertisement; it does not invent a second route or silently move every reusable request onto the API host.- Docs-host
--header,--bearerand--basiccredentials authenticate the FlexDoc page/execute endpoint only and are never copied onto direct target API requests. flexdoc buildwrites a.flexdoc-generatedmarker; replacing an unrelated existing output directory requires--force. External references are bundled into generated output.flexdoc serve --watchrebuilds the root OpenAPI input and live-reloads connected browser pages.
customJs is a generated/standalone host-page hook. The React FlexDoc component applies customCss and accepts root customStyles, but it does not eval options.customJs. The browser Playground therefore exposes CSS/styles/logo configuration and intentionally has no arbitrary JavaScript box.
Runner artifact parsing remains fail-closed: malformed or migration-requiring data, duplicate IDs, out-of-scope entities and in-memory file payloads are rejected rather than silently converted into a different request model.
Current boundaries
- Host execution is privileged outbound egress from the API host. Enable it only with explicit origins, protected docs and application traffic controls.
- Most native executors provide basic host transport. Cookie jars, mTLS, and signing stay Node-specific unless a host explicitly advertises them.
- Flask and Django serve the renderer. They do not emit contract validation or an execute route.
- NTLM/Negotiate intent is preserved in imported/workspace state but is not executable by current host executors.
- API Client scripts are trusted local JavaScript, not a security sandbox; saved workspace secrets are stored as entered in the browser origin.
- Runner artifacts may contain credentials and environment values. Treat them as sensitive configuration.
- Swagger/OpenAPI 2.0 is not accepted; integrations should provide OpenAPI 3.x.
For implementation detail, see the host-execution contract ↗, operations guidance ↗, and release notes.