Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
137 commits
Select commit Hold shift + click to select a range
850706f
feat(openapi-typescript): generate-client — typed, zero-dependency Op…
Marshevskyy Jun 15, 2026
6aeb52b
docs(cli): update text formatting
JLekawa Jun 17, 2026
2e5ae8d
Apply suggestions from code review
JLekawa Jun 17, 2026
ae5cebe
docs(cli): fix Markdoc errors, fix formatting
JLekawa Jun 17, 2026
3f38466
docs(realm): fix redirect error
JLekawa Jun 18, 2026
1adbf1e
docs(cli): fix redirect error
JLekawa Jun 18, 2026
0d974de
fix(openapi-typescript): point examples at the spec server + add test…
Marshevskyy Jun 22, 2026
7efcb23
Merge origin/main into feat/ts-client-gen
Marshevskyy Jun 22, 2026
e53e0b1
docs(generate-client): strip trailing spaces to satisfy markdownlint …
Marshevskyy Jun 22, 2026
95adc1e
ci(docs): use vale filter_mode nofilter to survive large-PR diffs
Marshevskyy Jun 22, 2026
5afa6a5
test(generate-client): commit consumer api.ts so flat typecheck finds it
Marshevskyy Jun 22, 2026
adc413e
fix: formatting
Marshevskyy Jun 22, 2026
f44e269
fix: align root react/react-dom with main (19.x) to fix build-docs sn…
Marshevskyy Jun 22, 2026
212bb7f
ci(docs): use reviewdog local reporter for vale so large PRs don't 406
Marshevskyy Jun 22, 2026
34594a7
Update docs/@v2/commands/generate-client.md
Marshevskyy Jun 22, 2026
f0c810b
fix(openapi-typescript): explicit .js extensions in example imports; …
Marshevskyy Jun 22, 2026
041040e
chore: revert vale reporter change; drop branch-added coverage thresh…
Marshevskyy Jun 22, 2026
776d818
docs(openapi-typescript): add a Node (msw/node) variant to the mock e…
Marshevskyy Jun 23, 2026
0340e2d
chore: drop trailing comma in vitest.config.ts (oxfmt es5 normalization)
Marshevskyy Jun 23, 2026
8dad18b
fix(openapi-typescript): SSE — flush final frame and finish on clean …
Marshevskyy Jun 23, 2026
dab6d50
fix(openapi-typescript): empty generators list falls back to the defa…
Marshevskyy Jun 23, 2026
aab5c4a
fix(cli): generate-client only loads a config file when --config-file…
Marshevskyy Jun 23, 2026
b97f6ba
Merge remote-tracking branch 'origin/main' into feat/ts-client-gen
Marshevskyy Jun 23, 2026
840c33a
fix: formatting
Marshevskyy Jun 23, 2026
f7dec25
fix(openapi-typescript): drain a retried response body before the nex…
Marshevskyy Jun 23, 2026
6532520
fix(openapi-typescript): regenerate programmatic example with the bod…
Marshevskyy Jun 24, 2026
914d1c6
fix(openapi-typescript): SSE reconnects on a transport failure openin…
Marshevskyy Jun 24, 2026
28a9c05
test(openapi-typescript): move examples drift test under generate-cli…
Marshevskyy Jun 24, 2026
3a0754b
refactor(openapi-typescript): drop *.config.ts config-file support an…
Marshevskyy Jun 26, 2026
69393cf
refactor!: rename @redocly/openapi-typescript → @redocly/client-gener…
Marshevskyy Jun 26, 2026
ba801b4
Merge remote-tracking branch 'origin/main' into feat/ts-client-gen
Marshevskyy Jun 30, 2026
977e19d
fix(client-generator): serialize request body after the onRequest chain
Marshevskyy Jun 30, 2026
448a592
feat(client-generator): operation context on requests + baked publish…
Marshevskyy Jun 30, 2026
b4930f2
fix: formatting
Marshevskyy Jun 30, 2026
18fe9c3
fix(client-generator): resolve CodeQL alerts (ReDoS, URL/stack-trace,…
Marshevskyy Jun 30, 2026
ee13cb5
docs(client-generator): fix --setup section link fragment (MD051)
Marshevskyy Jun 30, 2026
4b7b44a
docs(client-generator): use imperative --setup heading (Vale HeaderGe…
Marshevskyy Jun 30, 2026
7dbd311
fix(client-generator): accept relative base-url; resolve CLI --setup …
Marshevskyy Jun 30, 2026
b55d394
fix(client-generator): serialize multipart body after the onRequest c…
Marshevskyy Jun 30, 2026
9946803
fix(client-generator): resolve generateClient setup path from cwd, li…
Marshevskyy Jun 30, 2026
18705f9
fix: formatting
Marshevskyy Jun 30, 2026
58573fd
refactor(client-generator): move examples under tests/e2e/generate-cl…
Marshevskyy Jul 1, 2026
abff0c3
docs(client-generator): simplify and restructure the command reference
Marshevskyy Jul 1, 2026
7b87b6c
refactor(client-generator): rename the input positional/field to api
Marshevskyy Jul 1, 2026
2b87a3f
feat(core): register client + clientOutput in the redocly.yaml config…
Marshevskyy Jul 2, 2026
3596d12
refactor(client-generator): rename baseUrl to serverUrl
Marshevskyy Jul 2, 2026
9379791
feat(cli): generate-client reads the client config block; three invoc…
Marshevskyy Jul 2, 2026
37b5949
test(client-generator): move examples + e2e to the new client config …
Marshevskyy Jul 2, 2026
2159ba5
refactor(client-generator): rename setBaseUrl to setServerUrl
Marshevskyy Jul 2, 2026
794649e
docs(client-generator): document the client config model + serverUrl
Marshevskyy Jul 2, 2026
4d55775
refactor(core): type client + clientOutput on the resolved config
Marshevskyy Jul 2, 2026
582b3e4
chore: drop the body-serialization changeset
Marshevskyy Jul 2, 2026
953206c
refactor(cli): use openapi-core pluralize for the generate-client sum…
Marshevskyy Jul 2, 2026
829839e
refactor(cli): drop explanatory comments in the generators coerce
Marshevskyy Jul 2, 2026
5deef0d
refactor(client-generator): rename ir/ to intermediate-representation/
Marshevskyy Jul 2, 2026
5728f00
fix(client-generator): correct stale/misplaced comments and a dead __…
Marshevskyy Jul 2, 2026
f8faebf
chore: stop blanket-ignoring e2e yaml in oxfmt
Marshevskyy Jul 2, 2026
7197b02
style: run oxfmt across the client-generator branch
Marshevskyy Jul 2, 2026
4743b58
test(client-generator): compile generated clients under nodenext, not…
Marshevskyy Jul 2, 2026
6ea02b4
refactor(client-generator): expose everything from the single package…
Marshevskyy Jul 2, 2026
e1d9098
test(client-generator): use outdent for inline specs and consumer scr…
Marshevskyy Jul 2, 2026
447b4e9
docs: add generate-client to the v2 sidebar
Marshevskyy Jul 2, 2026
da30a43
docs: split generate-client into command, client-usage, and config pages
Marshevskyy Jul 2, 2026
fe64930
docs: keep generate-client as a single command page
Marshevskyy Jul 2, 2026
25d8f18
docs: drop the extra generate-client sidebar entries
Marshevskyy Jul 2, 2026
6f46549
docs: client usage as a guide, client config under configuration/refe…
Marshevskyy Jul 2, 2026
4158cdc
fix(client-generator): address cursor-bot findings (serverUrl, dup ou…
Marshevskyy Jul 2, 2026
6f21aa5
docs(client-generator): note retry resend + use()/configure middlewar…
Marshevskyy Jul 2, 2026
3f0323c
Update README.md
Marshevskyy Jul 3, 2026
59990e9
docs(client-generator): new ard for msw vs mock server
Marshevskyy Jul 3, 2026
d6f7e80
feat(client-generator): runtime module + descriptor client (--runtime…
Marshevskyy Jul 6, 2026
b5dda87
Merge remote-tracking branch 'origin/main' into feat/ts-client-gen
Marshevskyy Jul 6, 2026
273c7a7
docs: wrap overlong line in the generated-client guide (markdownlint …
Marshevskyy Jul 6, 2026
303bd1c
fix: align @redocly/client-generator's openapi-core dependency with t…
Marshevskyy Jul 6, 2026
93d7ee1
fix(generate-client): restrict serverUrl to http(s)/root-relative; re…
Marshevskyy Jul 6, 2026
b472709
feat(client-generator): auto-pagination — declared, statically verifi…
Marshevskyy Jul 8, 2026
eb526f7
feat(client-generator): nested-facade example + output-path interpola…
Marshevskyy Jul 8, 2026
1bd0464
fix: versions
Marshevskyy Jul 8, 2026
be55f66
Merge remote-tracking branch 'origin/main' into feat/ts-client-gen
Marshevskyy Jul 8, 2026
489ed53
fix: stop oxfmt reformatting generated pagination-consumer artifacts
Marshevskyy Jul 8, 2026
504696d
fix(respect): wait for json-server readiness in the local-json-server…
Marshevskyy Jul 8, 2026
3f09b2b
fix(client-generator): result-mode pagination must not throw on succe…
Marshevskyy Jul 8, 2026
214b867
Merge remote-tracking branch 'origin/main' into feat/ts-client-gen
Marshevskyy Jul 8, 2026
bf5f82b
ci: cap e2e parallelism to keep the runner within memory
Marshevskyy Jul 8, 2026
5a424ec
test(client-generator): refresh base/sse consumer fixtures for the pa…
Marshevskyy Jul 8, 2026
fc32f83
fix: change ci runner to gh hosted
Marshevskyy Jul 8, 2026
2989dc8
fix(client-generator): deep-merge pagination when layering client con…
Marshevskyy Jul 8, 2026
be92b1e
ci: split e2e into two sharded jobs
Marshevskyy Jul 9, 2026
0ef1ba1
docs(client-generator): fix README generateClient import and list the…
Marshevskyy Jul 9, 2026
45887e6
fix: vitest thresholds
Marshevskyy Jul 10, 2026
a9eb026
fix(client-generator): address PR review comments
Marshevskyy Jul 10, 2026
f649e42
feat(client-generator): repeatable --generator flag; resolve per-alia…
Marshevskyy Jul 10, 2026
47a44fe
fix(client-generator): update stale golden + assertions for the revie…
Marshevskyy Jul 10, 2026
4f9bde4
test(client-generator): regenerate inline consumer fixtures for the r…
Marshevskyy Jul 10, 2026
698d123
fix(client-generator): encode cookie auth, coerce string pagination o…
Marshevskyy Jul 10, 2026
895908a
docs(changeset): shorten the client-generator changeset to what's added
Marshevskyy Jul 13, 2026
71fbff9
fix(cli): resolve generate-client apis via getFallbackApisOrExit like…
Marshevskyy Jul 13, 2026
7d0fc4c
chore(cli): restore the original build banner comment
Marshevskyy Jul 13, 2026
1015231
refactor(cli): move generate-client comments into docs and yargs desc…
Marshevskyy Jul 13, 2026
5152c2b
refactor(cli): return each serverUrl validation case explicitly
Marshevskyy Jul 13, 2026
51550d8
refactor(cli): read the effective client block via config.forAlias
Marshevskyy Jul 13, 2026
c589573
fix(client-generator): UTF-8-safe basic auth encoding and Headers-ins…
Marshevskyy Jul 13, 2026
d66f14c
refactor(core): remove needless client config comments
Marshevskyy Jul 13, 2026
3cbe9b8
fix(cli): opt apis into generate-client fan-out via clientOutput too
Marshevskyy Jul 13, 2026
8c5a54b
fix(client-generator): put the types condition first in package exports
Marshevskyy Jul 13, 2026
41a96e7
Merge remote-tracking branch 'origin/main' into feat/ts-client-gen
Marshevskyy Jul 13, 2026
f9904f3
fix(core): layer a per-api client block over the top-level one field …
Marshevskyy Jul 13, 2026
1c6fe7e
fix(client-generator): fail closed on oversized SSE frames instead of…
Marshevskyy Jul 13, 2026
a381825
fix(client-generator): skip the optional-auth marker when resolving o…
Marshevskyy Jul 14, 2026
e25b149
fix(core): keep the pagination block additive when layering per-api c…
Marshevskyy Jul 14, 2026
36c569f
fix(client-generator): let CommonJS projects require() the package ru…
Marshevskyy Jul 14, 2026
0896157
Merge remote-tracking branch 'origin/main' into feat/ts-client-gen
Marshevskyy Jul 14, 2026
1a16633
fix(client-generator): apply the first configured security alternativ…
Marshevskyy Jul 14, 2026
f5776cf
fix(client-generator): cancel the abandoned body when onResponse repl…
Marshevskyy Jul 14, 2026
3aea0d0
feat(client-generator): zod runtime validation — operationSchemas map…
Marshevskyy Jul 15, 2026
7958fbb
fix(client-generator): declaration-safe operationSchemas and omit on …
Marshevskyy Jul 15, 2026
3bef857
Update docs/@v2/configuration/reference/client.md
Marshevskyy Jul 16, 2026
cebc122
Update docs/@v2/configuration/reference/client.md
Marshevskyy Jul 16, 2026
1b7ce53
Update docs/@v2/configuration/reference/client.md
Marshevskyy Jul 16, 2026
8bca18f
test(cli): prove shared generator defaults survive per-api client ove…
Marshevskyy Jul 16, 2026
fae2394
refactor(client-generator): match apiKey scheme kinds exactly
Marshevskyy Jul 16, 2026
238612b
test(client-generator): share the example spec, gitignore generated c…
Marshevskyy Jul 17, 2026
de9b41f
test(client-generator): extract shared e2e helpers and stop committin…
Marshevskyy Jul 17, 2026
26455fa
test(client-generator): drop redundant unit tests and runtime-embeddi…
Marshevskyy Jul 17, 2026
3874370
refactor(client-generator): dedupe emitter helpers, inline the writer…
Marshevskyy Jul 17, 2026
1970eb7
fix(cli): validate the --setup flag like the config setup and complet…
Marshevskyy Jul 17, 2026
617f1a1
docs(cli): use semantic line breaks in the generate-client guide and …
Marshevskyy Jul 17, 2026
94a7339
test(cli): drive the redocly-config e2e suite with a minimal inline s…
Marshevskyy Jul 17, 2026
ed231e1
docs(client-generator): fold the customization example into configure…
Marshevskyy Jul 17, 2026
38f807b
test(client-generator): make fixture arguments explicit and dedupe th…
Marshevskyy Jul 17, 2026
c6266bc
Potential fix for pull request finding 'CodeQL / Workflow does not co…
Marshevskyy Jul 17, 2026
0f71a56
fix(client-generator): resolve server-URL variables, match pagination…
Marshevskyy Jul 17, 2026
a8deb80
fix(client-generator): snapshot release
Marshevskyy Jul 20, 2026
d4c6f3b
fix(client-generator): snapshot release p2
Marshevskyy Jul 20, 2026
c1e7ce0
chore(examples): reference the published client-generator snapshot in…
Marshevskyy Jul 20, 2026
75b1cd6
fix(client-generator): publish the CLI snapshot before client-generator
Marshevskyy Jul 20, 2026
f11d5af
test(cli): per-api runtime-only block inherits shared generators and …
Marshevskyy Jul 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
9 changes: 9 additions & 0 deletions .changeset/client-generator.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
'@redocly/client-generator': minor
'@redocly/openapi-core': minor
'@redocly/cli': minor
---

Added an experimental `generate-client` command that generates a typed, zero-dependency TypeScript client from an OpenAPI description — with auth, retries, middleware, typed SSE streaming, auto-pagination, and multipart support.
The `--generator` option emits companion modules from the same description: `zod`, `tanstack-query`, `swr`, `transformers`, and `mock`.
See the [`generate-client` command reference](https://redocly.com/docs/cli/commands/generate-client) and the [Use the generated client](https://redocly.com/docs/cli/guides/use-generated-client) guide.
16 changes: 13 additions & 3 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,11 @@ jobs:
cache: npm
registry-url: https://registry.npmjs.org

# Install before the version bump: npm links workspace packages only while
# their versions still match the dependency specs in package.json files.
- name: Install dependencies
run: npm install

- name: Update package versions
run: |
TIMESTAMP=$(date +%s)
Expand All @@ -218,6 +223,10 @@ jobs:
jq ".version = \"$VERSION\"" packages/respect-core/package.json > tmp.json && mv tmp.json packages/respect-core/package.json
jq ".dependencies[\"@redocly/openapi-core\"] = \"$VERSION\"" packages/respect-core/package.json > tmp.json && mv tmp.json packages/respect-core/package.json

# Update Client Generator package version and dependencies
jq ".version = \"$VERSION\"" packages/client-generator/package.json > tmp.json && mv tmp.json packages/client-generator/package.json
jq ".dependencies[\"@redocly/openapi-core\"] = \"$VERSION\"" packages/client-generator/package.json > tmp.json && mv tmp.json packages/client-generator/package.json

# Update CLI package version
jq ".version = \"$VERSION\"" packages/cli/package.json > tmp.json && mv tmp.json packages/cli/package.json

Expand All @@ -236,9 +245,6 @@ jobs:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.pull_request.number }}

- name: Install dependencies
run: npm install

- name: Build packages
run: npm run compile

Expand All @@ -258,3 +264,7 @@ jobs:
npm run prepare:publish-dir
npm publish ./.publish --tag snapshot
npm run clean:publish-dir
sleep 10

cd ../client-generator
npm publish --tag snapshot
43 changes: 41 additions & 2 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ on:
branches:
- main

permissions:
contents: read

env:
CI: true
REDOCLY_TELEMETRY: off
Expand All @@ -32,8 +35,44 @@ jobs:
continue-on-error: true # Do not fail if there is an error during reporting
uses: davelosert/vitest-coverage-report-action@d63aa97db4c0319f304f1787689de1ca548365cf # v2.11.1

- name: E2E Tests
run: npm run e2e
e2e:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the reason for this change? The e2e job isn't a required check in the repo's settings, and it would be possible to merge a PR even with the job failing.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We had canceled GH job without any reason. I tried to do deep research, this is a summary:

Tets started failing after we added more tests, there is no specific test impacting this. Only number of tests...
AI made some research:
What I ruled out with live in-job instrumentation (every metric healthy at the moment of cancel): RAM (~14 GB free), disk (~90 GB free), CPU/load, processes (~190), threads (~480), file descriptors (~2 500 of 65 536), sockets/TIME-WAIT, inodes (18 M free), kernel OOM (none). Also ruled out: parallel contention (serial --maxWorkers=1 still cancels, just later), network, log volume, and any single test (all pass locally and individually).

The decisive piece — from the runner's own _diag logs: the job token renews successfully every 60 s and console uploads succeed (1/1) right up to the cancel. So the runner stays healthy and connected; GitHub's service is deliberately cancelling a healthy job. The exact service-side reason isn't observable from inside — when the service cancels, it tears the step down and stops accepting console output, so streamed diag lines can't upload. That last mile needs GitHub support or org runner-group admin visibility

# The e2e suite is split across shards so no single runner carries the whole set.
# Running all suites in one step was cancelled mid-run by the Actions service once the
# generate-client suites grew past ~28 (a healthy runner, no resource exhaustion);
# each shard stays well under that.
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
shard: [1, 2]
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: 24
cache: npm
- name: Install dependencies
run: npm ci
- name: E2E Tests (shard ${{ matrix.shard }}/2)
run: npm run e2e -- --shard=${{ matrix.shard }}/2

examples:
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
# The examples gitignore their generated clients (only zero-install-quickstart commits
# its canonical copy), so this job regenerates every client and type-checks the
# hand-written consumer code against it.
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: 24
cache: npm
- name: Install dependencies
run: npm ci
- name: Regenerate example clients
run: npm run examples:regen -w @redocly/client-generator
- name: Type-check examples
run: npm run typecheck:examples -w @redocly/client-generator

code-style-check:
runs-on: ubuntu-latest
Expand Down
3 changes: 3 additions & 0 deletions .oxfmtrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@
"packages/respect-core/src/modules/runtime-expressions/abnf-parser.js",
"packages/core/src/rules/common/__tests__/fixtures/invalid-yaml.yaml",
"tests/performance/api-definitions/",
"tests/e2e/generate-client/examples/*/src/api/",
"tests/e2e/generate-client/*-consumer/api*.ts",
"tests/smoke/**/*.yaml",
"snapshot*.txt",
"tests/e2e/generate-client/*.snapshot.ts",
"*.html",
"*.hbs",
"*.toml",
Expand Down
19 changes: 18 additions & 1 deletion .oxlintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,15 @@
"builtin": true,
"es2026": true
},
"ignorePatterns": ["packages/*/lib/**", "*.js", "*.cjs"],
"ignorePatterns": [
"packages/*/lib/**",
"*.js",
"*.cjs",
"tests/e2e/generate-client/examples/*/src/api/**",
"tests/e2e/generate-client/examples/*/generate.ts",
"tests/e2e/generate-client/*.snapshot.ts",
"tests/e2e/generate-client/*-consumer/api.ts"
],
"rules": {
"eslint/no-array-constructor": "error",
"eslint/no-case-declarations": "error",
Expand Down Expand Up @@ -68,6 +76,15 @@
"rules": {
"eslint/no-console": "allow"
}
},
{
"files": [
"tests/e2e/generate-client/examples/*/src/**",
"tests/e2e/generate-client/examples/*/worker.ts"
],
"rules": {
"eslint/no-console": "allow"
}
}
]
}
1 change: 1 addition & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ Run `npm test` to start both unit and e2e tests (and additionally typecheck the
### Unit tests

Run unit tests with this command: `npm run unit`.
This command runs the suite for every package whose tests match the discovery glob — there is no per-package `npm test` script.

Unit tests in the **cli** package are sensitive to top-level configuration file (**redocly.yaml**).

Expand Down
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,21 @@ Respect is Redocly's community-edition product. Looking for something more? We a

Learn more about [Respect](https://redocly.com/respect) and [get started with API contract testing](https://redocly.com/docs/respect/get-started).

### Generate a TypeScript client

> ⚠️ **Experimental** — flags, output, and configuration may change in any minor release until declared stable.

Turn an OpenAPI description (3.0/3.1/3.2 or Swagger 2.0) into a typed TypeScript client with the `generate-client` command.
The emitted client has zero runtime dependencies and runs in browsers, Node, Bun, Deno, and edge runtimes.

```sh
redocly generate-client openapi.yaml --output src/client.ts
```

Inline types plus a typed client instance and one async function per operation, with auth, opt-in abort-aware retries, middleware, and typed Server-Sent Events.
The same command can also emit Zod schemas, TanStack Query / SWR hooks, MSW mocks, and more via `--generators`.
For detailed information, read the [ `generate-client` docs](./docs/@v2/commands/generate-client.md).

### Transform an OpenAPI description

If your OpenAPI description isn't everything you hoped it would be, enhance it with the Redocly [decorators](https://redocly.com/docs/cli/decorators) feature.
Expand Down
118 changes: 118 additions & 0 deletions docs/@v2/commands/generate-client.md
Comment thread
vadyvas marked this conversation as resolved.
Comment thread
vadyvas marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
---
slug:
- /docs/cli/commands/generate-client
---

# `generate-client`

{% admonition type="warning" name="Experimental" %}
`generate-client` is **experimental**: its flags, generated output, configuration schema, and custom-generator API may change in any minor release until it's stable.
We'd love your feedback while we stabilize it.
{% /admonition %}

Generate a typed TypeScript client from an OpenAPI 3.x description.
Swagger 2.0 descriptions are also accepted — normalized to the 3.x shape before generation.

The generated client has **zero runtime dependencies** by default — it uses only web-standard APIs (`fetch`, `AbortController`, `URLSearchParams`, …), so it runs in browsers, Node, Bun, Deno, and edge runtimes.
By default it emits a single self-contained file with inline types and one async function per operation; opt in to a versioned, npm-updatable runtime instead with [`--runtime package`](#runtime-distribution).

This page covers running the command; for the generated client's runtime API (auth, error handling, middleware, retries, and the add-on generators) see [Use the generated client](../guides/use-generated-client.md).

## Usage

```sh
redocly generate-client # every api with a `client` block or `clientOutput`
redocly generate-client cafe # a single `apis:` alias from redocly.yaml
redocly generate-client openapi.yaml -o dist/client.ts # a file path or URL
```

With no argument, a client is generated for every api that declares a `client` block or a `clientOutput` under `apis:` (see [`client` configuration](../configuration/reference/client.md)).
Otherwise `<api>` is a file path, a URL, or an [`apis:` alias](../configuration/index.md), resolved the same way as in other commands such as `bundle` and `lint`: an alias — or a path matching an api's `root` — uses that api's `client` block and `clientOutput`, while an unmatched path/URL uses the top-level `client` defaults.

## Options

| Option | Type | Description |
| ------------------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `api` | `string` | OpenAPI description file path, URL, or an `apis:` alias. Omit it to generate for every api that has a `client` block or `clientOutput`. |
| `--output`, `-o` | `string` | Output path (must end in `.ts`); the entry file in multi-file modes. Defaults to the api's `clientOutput`, else `<name>.client.ts` in the config dir. Not allowed when generating for multiple apis. |
| `--output-mode` | `string` | File layout: `single` (default) or `split`. See [Output modes](#output-modes). |
| `--runtime` | `string` | `inline` (default, self-contained file — zero runtime dependencies) or `package` (imports the runtime from `@redocly/client-generator`; engine fixes arrive via `npm update`). See [Runtime distribution](#runtime-distribution). |
| `--generator` | `string[]` | Generator to run — a built-in name or a custom generator's path/package; repeat the flag to run several (default `sdk`). See [Generators](../guides/use-generated-client.md#generators). |
| `--args-style` | `string` | Operation inputs: `flat` (default, positional) or `grouped` (a single `vars` object). See [Argument style](../guides/use-generated-client.md#argument-style). |
| `--enum-style` | `string` | Named string enums: `const-object` (default, `as const` object + union) or `union` (union only). |
| `--error-mode` | `string` | `throw` (default, throws `ApiError`) or `result` (returns `{ data, error, response }`). See [Error handling](../guides/use-generated-client.md#error-handling). |
| `--date-type` | `string` | `date`/`date-time` fields as `string` (default) or `Date` (pair with the `transformers` generator). |
| `--query-framework` | `string` | TanStack Query adapter: `react` (default), `vue`, `svelte`, or `solid`. |
| `--mock-data` | `string` | `mock` generator data: `baked` (default, deterministic literals) or `faker` (`@faker-js/faker` calls). |
| `--mock-seed` | `number` | Seed for `faker`-mode mocks, for reproducible data. Ignored in `baked` mode. |
| `--server-url` | `string` | Override the server URL inlined into the runtime. Defaults to `servers[0].url`. Accepts absolute (`https://api.example.com`) or relative (`/v1`). |
| `--setup` | `string` | Path to a publisher setup module baked into the client. See [Publisher defaults](../guides/use-generated-client.md#publisher-defaults). |
| `--config` | `string` | Path to the `redocly.yaml` (the `client` config and `apis:` live there). Defaults to the one in the working directory. |

## Configuration
Comment thread
vadyvas marked this conversation as resolved.

Instead of passing flags every time, keep the settings in `redocly.yaml` under a top-level `client` block and per-API `apis.<name>.client` / `clientOutput`.
CLI flags take precedence over the configuration.
A per-API `client` block overrides the top-level `client` field by field; unspecified fields fall back to the top-level defaults.
See [`client` configuration](../configuration/reference/client.md) for the full reference.

Auto-pagination has **no CLI flag**: it's declared as structured configuration — [`client.pagination`](../configuration/reference/client.md#pagination) in `redocly.yaml`, or the equivalent `x-pagination` operation extension in the spec — and paginated operations gain typed `.pages()`/`.items()` async iterators.
See [Pagination in the usage guide](../guides/use-generated-client.md#pagination).

## Output modes

`--output-mode` controls how the client is split across files:

- `single` (default) — one file (self-contained with the default `inline` runtime).
- `split` — two files: the schema types and type guards move to a sibling `<name>.schemas.ts`, and the entry file (everything else) re-exports them — so your imports are the same as in `single`.

`--output` names the entry file; the `.schemas.ts` sibling derives from its name and directory. Both modes work with both [runtimes](#runtime-distribution).

## Runtime distribution

`--runtime` controls where the client's engine (request building, auth, retries, middleware, SSE) lives:

- `inline` (default) — the same runtime source is embedded in the generated output (only the parts your API needs): self-contained, zero runtime dependencies.
- `package` — the generated file imports the runtime from `@redocly/client-generator` and contains only the types, pure-data operation descriptors, and thin call wrappers:

```ts
import {
createClient,
type OperationDescriptor,
type RequestOptions,
} from '@redocly/client-generator';

export const OPERATIONS = {
getOrderById: {
id: 'getOrderById',
method: 'GET',
path: '/orders/{orderId}',
tags: ['Orders'],
params: [
/* … */
],
},
// …
} as const satisfies Record<string, OperationDescriptor>;

export const client = createClient<Ops>(OPERATIONS, { serverUrl: 'https://api.example.com' });
export const { configure, use } = client;
export const getOrderById = (orderId: string, init: RequestOptions = {}) =>
client.getOrderById({ orderId }, init);
```

Choose `package` when you want engine fixes and improvements to arrive via `npm update @redocly/client-generator` — no regeneration, no diff in the generated file.
The trade: the consuming app must have `@redocly/client-generator` installed as a regular dependency.
Your application code is identical in both modes (same exports, same call shapes).

The `satisfies Record<string, OperationDescriptor>` line doubles as a **build-time version-skew guard**: an incompatible generated-file/runtime pair fails the consumer's `tsc` instead of misbehaving at runtime.

In both modes the generated module exports **both call styles** — the `client` instance (grouped-args methods) and the free-function operations (`--args-style` shapes those).
Both runtimes work with both [output modes](#output-modes) and every generator.

## Resources

- [Use the generated client](../guides/use-generated-client.md) — the runtime API and the add-on generators.
- [`client` configuration](../configuration/reference/client.md) — the `redocly.yaml` `client` block.
- [Lint command](./lint.md) to validate your API description before generating a client.
- [Bundle command](./bundle.md) to combine a multi-file description into a single input file.
1 change: 1 addition & 0 deletions docs/@v2/commands/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Documentation commands:
API management commands:

- [`bundle`](bundle.md) Bundle API description.
- [`generate-client`](generate-client.md) Generate a typed TypeScript client from an OpenAPI description [experimental feature].
- [`join`](join.md) Join API descriptions [experimental feature].
- [`score`](score.md) Score an API for integration simplicity and AI agent readiness.
- [`split`](split.md) Split API description into a multi-file structure.
Expand Down
12 changes: 12 additions & 0 deletions docs/@v2/configuration/reference/apis.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,18 @@ If your project contains multiple APIs, the `apis` configuration section allows
- Output file path
- When running `bundle` without specifying an API, the bundled API description is saved to this location.

---

- client
- [Client object](./client.md)
- Additional TypeScript client generation configuration for this API, used by the experimental `generate-client` command.

---

- clientOutput
- Output file path
- When running `generate-client` without specifying an API, the generated TypeScript client is saved to this location.

{% /table %}

## Examples
Expand Down
Loading
Loading