Technical Documentation: hey-api/openapi-ts
ℹ️ Provenance: Multi-Tier Ingestion · CodeWiki Reference
Overview (`README.md`)
About
Hey API is an ecosystem for turning API specifications into production-ready code. It's trusted by thousands of companies – from YC startups to Fortune 500 enterprises – and powers products used by millions worldwide.
This is the monorepo containing all open source Hey API packages. For package-specific documentation and quick start guides, see the individual repositories below.
Packages
| Package | Description |
|---|---|
openapi-ts |
TypeScript code generator with 20+ plugins for SDKs, Zod schemas, TanStack Query hooks, and more. |
[Manual](https://heyapi.dev/docs/openapi/typescript/get-started)
•
[npm](https://npmjs.com/package/@hey-api/openapi-ts) || openapi-python | Python code generator for SDKs and Pydantic models.
[Manual](https://heyapi.dev/docs/openapi/python/get-started)
•
[npm](https://npmjs.com/package/@hey-api/openapi-python) |Highlights
- production-grade code that compiles
- runs in any Node.js 22+ environment
- accepts any OpenAPI specification
- core plugins for SDKs
- HTTP clients for Fetch API, Axios, Angular, Next.js, Nuxt, HTTPX, and more
- Zod schemas, TanStack Query hooks, Pydantic models, and 20+ plugins to reduce third-party boilerplate
- highly customizable via plugins
Libraries
| Package | Description |
|---|---|
spec-types |
TypeScript definitions for OpenAPI and JSON Schema specifications with complete inline documentation. |
[npm](https://npmjs.com/package/@hey-api/spec-types) |Contributing
Want to see your code in products used by millions?
Start with our Contributing guide and release your first feature.
Sponsors
Partners behind the future of API tooling. Become a sponsor.
Gold
Silver
| fastapi.tiangolo.com | getunblocked.com |
|---|
Bronze
License
Released under the MIT License.
Overview (`.changeset/README.md`)
Changesets
Hello and welcome! This folder has been automatically generated by @changesets/cli, a build tool that works
with multi-package repos, or single-package repos to help you version and publish your code. You can
find the full documentation for it in our repository
We have a quick list of common questions to get you started engaging with this project in
our documentation
Overview (`examples/README.md`)
Examples
This directory contains integration examples demonstrating how to use @hey-api/openapi-ts with various frameworks, libraries, and client implementations.
Available Examples
- openapi-ts-angular - Angular integration with common HTTP client
- openapi-ts-angular-common - Angular with @angular/common/http
- openapi-ts-axios - Using Axios client
- openapi-ts-fastify - Fastify server integration
- openapi-ts-fetch - Native Fetch API client
- openapi-ts-next - Next.js integration
- openapi-ts-nuxt - Nuxt.js integration with plugin
- openapi-ts-ofetch - Using ofetch client
- openapi-ts-openai - OpenAI API integration
- openapi-ts-pinia-colada - Vue with Pinia Colada state management
- openapi-ts-sample - Sample/template example (excluded from CI)
- openapi-ts-tanstack-angular-query-experimental - Angular with TanStack Query
- openapi-ts-tanstack-react-query - React with TanStack Query
- openapi-ts-tanstack-svelte-query - Svelte with TanStack Query
- openapi-ts-tanstack-vue-query - Vue with TanStack Query
Generated Code
All examples (except openapi-ts-sample) contain generated client code that is committed to the repository. This ensures:
- Examples always reflect the current state of the code generator
- Changes to the code generator are visible in pull requests
- CI can verify that examples are kept up-to-date
Regenerating Examples
After making changes to the core packages, regenerate all example code:
pnpm examples:updateThis command will run openapi-ts for each example that has an openapi-ts script in its package.json.
Verifying Examples
To check if all examples are up-to-date with the current codebase:
pnpm examples:checkThis check is also run automatically in CI. If it fails, run pnpm examples:update and commit the changes.
Running Examples
Each example can be run individually using the example script:
# Run dev server for fetch example
pnpm example fetch dev
# Build fetch example
pnpm example fetch buildOr directly using pnpm filters:
pnpm --filter @example/openapi-ts-fetch devCreating New Examples
When creating a new example:
- Create a new directory in
examples/ - Add an
openapi-tsscript topackage.json - Run
pnpm examples:updateto create initial generated code - Commit both the source and generated code
- The example will automatically be included in CI checks
Excluding Examples
To exclude an example from CI (like openapi-ts-sample):
- Remove the
openapi-tsscript frompackage.json, or - Update the exclusion filters in
package.jsonscripts and.github/workflows/ci.yml
Overview (`examples/openapi-ts-angular-common/README.md`)
Angular
This project was generated using Angular CLI version 19.2.15.
Development server
To start a local development server, run:
ng serveOnce the server is running, open your browser and navigate to http://localhost:4200/. The application will automatically reload whenever you modify any of the source files.
Code scaffolding
Angular CLI includes powerful code scaffolding tools. To generate a new component, run:
ng generate component component-nameFor a complete list of available schematics (such as components, directives, or pipes), run:
ng generate --helpBuilding
To build the project run:
ng buildThis will compile your project and store the build artifacts in the dist/ directory. By default, the production build optimizes your application for performance and speed.
Running unit tests
To execute unit tests with the Karma test runner, use the following command:
ng testRunning end-to-end tests
For end-to-end (e2e) testing, run:
ng e2eAngular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs.
Additional Resources
For more information on using the Angular CLI, including detailed command references, visit the Angular CLI Overview and Command Reference page.
Overview (`examples/openapi-ts-angular/README.md`)
Angular
This project was generated using Angular CLI version 19.2.15.
Development server
To start a local development server, run:
ng serveOnce the server is running, open your browser and navigate to http://localhost:4200/. The application will automatically reload whenever you modify any of the source files.
Code scaffolding
Angular CLI includes powerful code scaffolding tools. To generate a new component, run:
ng generate component component-nameFor a complete list of available schematics (such as components, directives, or pipes), run:
ng generate --helpBuilding
To build the project run:
ng buildThis will compile your project and store the build artifacts in the dist/ directory. By default, the production build optimizes your application for performance and speed.
Running unit tests
To execute unit tests with the Karma test runner, use the following command:
ng testRunning end-to-end tests
For end-to-end (e2e) testing, run:
ng e2eAngular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs.
Additional Resources
For more information on using the Angular CLI, including detailed command references, visit the Angular CLI Overview and Command Reference page.
Overview (`examples/openapi-ts-next/README.md`)
This is a Next.js project bootstrapped with create-next-app.
Getting Started
First, run the development server:
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun devOpen http://localhost:3000 with your browser to see the result.
You can start editing the page by modifying app/page.tsx. The page auto-updates as you edit the file.
This project uses next/font to automatically optimize and load Geist, a new font family for Vercel.
Learn More
To learn more about Next.js, take a look at the following resources:
- Next.js Documentation - learn about Next.js features and API.
- Learn Next.js - an interactive Next.js tutorial.
You can check out the Next.js GitHub repository - your feedback and contributions are welcome!
Deploy on Vercel
The easiest way to deploy your Next.js app is to use the Vercel Platform from the creators of Next.js.
Check out our Next.js deployment documentation for more details.
Overview (`examples/openapi-ts-nuxt/README.md`)
Nuxt Minimal Starter
Look at the Nuxt documentation to learn more.
Setup
Make sure to install dependencies:
# npm
npm install
# pnpm
pnpm install
# yarn
yarn install
# bun
bun installDevelopment Server
Start the development server on http://localhost:3000:
# npm
npm run dev
# pnpm
pnpm dev
# yarn
yarn dev
# bun
bun run devProduction
Build the application for production:
# npm
npm run build
# pnpm
pnpm build
# yarn
yarn build
# bun
bun run buildLocally preview production build:
# npm
npm run preview
# pnpm
pnpm preview
# yarn
yarn preview
# bun
bun run previewCheck out the deployment documentation for more information.
Overview (`examples/openapi-ts-pinia-colada/README.md`)
@hey-api/openapi-ts with Pinia Colada Example
This example demonstrates how to use @hey-api/openapi-ts with Pinia Colada for Vue 3 applications.
Recommended IDE Setup
VSCode + Volar (and disable Vetur).
Type Support for `.vue` Imports in TS
TypeScript cannot handle type information for .vue imports by default, so we replace the tsc CLI with vue-tsc for type checking. In editors, we need Volar to make the TypeScript language service aware of .vue types.
Customize configuration
See Vite Configuration Reference.
Project Setup
pnpm installCompile and Hot-Reload for Development
pnpm devType-Check, Compile and Minify for Production
pnpm buildRun Unit Tests with [Vitest](https://vitest.dev)
pnpm test:unitOverview (`examples/openapi-ts-tanstack-angular-query-experimental/README.md`)
OpenapiTsTanstackAngularQueryExperimental
This project was generated with Angular CLI version 18.2.7.
Development server
Run ng serve for a dev server. Navigate to http://localhost:4200/. The application will automatically reload if you change any of the source files.
Code scaffolding
Run ng generate component component-name to generate a new component. You can also use ng generate directive|pipe|service|class|guard|interface|enum|module.
Build
Run ng build to build the project. The build artifacts will be stored in the dist/ directory.
Running unit tests
Run ng test to execute the unit tests via Karma.
Running end-to-end tests
Run ng e2e to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities.
Further help
To get more help on the Angular CLI use ng help or go check out the Angular CLI Overview and Command Reference page.
Overview (`examples/openapi-ts-tanstack-svelte-query/README.md`)
create-svelte
Everything you need to build a Svelte project, powered by create-svelte.
Creating a project
If you're seeing this, you've probably already done this step. Congrats!
# create a new project in the current directory
npm create svelte@latest
# create a new project in my-app
npm create svelte@latest my-appDeveloping
Once you've created a project and installed dependencies with npm install (or pnpm install or yarn), start a development server:
npm run dev
# or start the server and open the app in a new browser tab
npm run dev -- --openBuilding
To create a production version of your app:
npm run buildYou can preview the production build with npm run preview.
To deploy your app, you may need to install an adapter for your target environment.
Overview (`examples/openapi-ts-tanstack-vue-query/README.md`)
vue-project
This template should help get you started developing with Vue 3 in Vite.
Recommended IDE Setup
VSCode + Volar (and disable Vetur).
Type Support for `.vue` Imports in TS
TypeScript cannot handle type information for .vue imports by default, so we replace the tsc CLI with vue-tsc for type checking. In editors, we need Volar to make the TypeScript language service aware of .vue types.
Customize configuration
See Vite Configuration Reference.
Project Setup
pnpm installCompile and Hot-Reload for Development
pnpm devType-Check, Compile and Minify for Production
pnpm buildRun Unit Tests with [Vitest](https://vitest.dev)
pnpm test:unitOverview (`packages/codegen-core/README.md`)
Notice
This is an internal framework. Visit Hey API to discover our products.
Contributing
Want to see your code in products used by millions?
Start with our Contributing guide and release your first feature.
Sponsors
Partners behind the future of API tooling. Become a sponsor.
Gold
Silver
| fastapi.tiangolo.com | getunblocked.com |
|---|
Bronze
License
Released under the MIT License.
Overview (`packages/json-schema-ref-parser/README.md`)
JSON Schema $Ref Parser
Parse, Resolve, and Dereference JSON Schema $ref pointers
Installation
Install using npm:
npm install @hey-api/json-schema-ref-parser
pnpm add @hey-api/json-schema-ref-parser
yarn add @hey-api/json-schema-ref-parser
bun add @hey-api/json-schema-ref-parserThe Problem:
You've got a JSON Schema with $ref pointers to other files and/or URLs. Maybe you know all the referenced files ahead
of time. Maybe you don't. Maybe some are local files, and others are remote URLs. Maybe they are a mix of JSON and YAML
format. Maybe some of the files contain cross-references to each other.
{
"definitions": {
"person": {
// references an external file
"$ref": "schemas/people/Bruce-Wayne.json"
},
"place": {
// references a sub-schema in an external file
"$ref": "schemas/places.yaml#/definitions/Gotham-City"
},
"thing": {
// references a URL
"$ref": "http://wayne-enterprises.com/things/batmobile"
},
"color": {
// references a value in an external file via an internal reference
"$ref": "#/definitions/thing/properties/colors/black-as-the-night"
}
}
}The Solution:
JSON Schema $Ref Parser is a full JSON Reference
and JSON Pointer implementation that crawls even the most
complex JSON Schemas and gives you simple, straightforward
JavaScript objects.
- Use JSON or YAML schemas — or even a mix of both!
- Supports
$refpointers to external files and URLs, as well as custom sources such as databases - Can bundle multiple files into a single schema that only has internal
$refpointers - Can dereference your schema, producing a plain-old JavaScript object that's easy to work with
- Supports circular references, nested references,
back-references, and cross-references between files - Maintains object reference equality —
$refpointers to the same value always resolve to the same object
instance - Compatible with Node LTS and beyond, and all major web browsers on Windows, Mac, and Linux
New in this fork (@hey-api)
- Multiple inputs with
bundleMany: Merge and bundle several OpenAPI/JSON Schema inputs (files, URLs, or raw objects) into a single schema. Components are prefixed to avoid name collisions, paths are namespaced on conflict, and$refs are rewritten accordingly.
import { $RefParser } from '@hey-api/json-schema-ref-parser';
const parser = new $RefParser();
const merged = await parser.bundleMany({
pathOrUrlOrSchemas: [
'./specs/a.yaml',
'https://example.com/b.yaml',
{ openapi: '3.1.0', info: { title: 'Inline' }, paths: {} },
],
});
// merged.components.* will contain prefixed names like a_<name>, b_<name>, etc.- Dereference hooks: Fine-tune dereferencing with
excludedPathMatcher(path) => booleanto skip subpaths andonDereference(path, value, parent, parentPropName)to observe replacements.
const parser = new $RefParser();
parser.options.dereference.excludedPathMatcher = (p) => p.includes('/example/');
parser.options.dereference.onDereference = (p, v) => {
// inspect p / v as needed
};
await parser.dereference({ pathOrUrlOrSchema: './openapi.yaml' });- Smart input resolution: You can pass a file path, URL, or raw schema object. If a raw schema includes
$id, it is used as the base URL for resolving relative$refs.
await new $RefParser().bundle({
pathOrUrlOrSchema: {
$id: 'https://api.example.com/openapi.json',
openapi: '3.1.0',
paths: {
'/ping': { get: { responses: { 200: { description: 'ok' } } } },
},
},
});Contributing
Want to see your code in products used by millions?
Start with our Contributing guide and release your first feature.
Sponsors
Partners behind the future of API tooling. Become a sponsor.
Gold
Silver
| fastapi.tiangolo.com | getunblocked.com |
|---|
Bronze
License
Released under the MIT License.
Overview (`packages/nuxt/README.md`)
Features
- seamless integration with
@hey-api/openapi-tsecosystem - type-safe response data and errors
- response data validation and transformation
- access to the original request and response
- granular request and response customization options
- minimal learning curve thanks to extending the underlying technology
- support bundling inside the generated output
- platform for automating codegen builds
Dashboard
Access your projects and OpenAPI specifications in the Hey API Platform.
Contributing
Want to see your code in products used by millions?
Start with our Contributing guide and release your first feature.
Documentation
Please visit our website for documentation, guides, migrating, and more.
Sponsors
Partners behind the future of API tooling. Become a sponsor.
Gold
Silver
| fastapi.tiangolo.com | getunblocked.com |
|---|
Bronze
Migrating
You can learn more on the Migrating page.
License
Released under the MIT License.
Overview (`packages/openapi-python/README.md`)
About
The OpenAPI to Python code generator.
Generate production-grade SDKs and Pydantic models.
Part of the Hey API ecosystem.
Features
- production-grade code that compiles
- runs in any Node.js 22+ environment
- accepts any OpenAPI specification
- core plugin for SDKs
- HTTP client for HTTPX
- highly customizable via plugins
- sync with Hey API Registry for spec management
Contributing
Want to see your code in products used by millions?
Start with our Contributing guide and release your first feature.
Sponsors
Partners behind the future of API tooling. Become a sponsor.
Gold
Silver
| fastapi.tiangolo.com | getunblocked.com |
|---|
Bronze
Quick Start
The fastest way to use @hey-api/openapi-python is via npx
npx @hey-api/openapi-python -i hey-api/backend -o src/clientCongratulations on creating your first client! 🎉 You can learn more about the generated files on the Output page.
Installation
You can download @hey-api/openapi-python from npm using your favorite package manager.
npm
npm install @hey-api/openapi-python -D -Epnpm
pnpm add @hey-api/openapi-python -D -Eyarn
yarn add @hey-api/openapi-python -D -Ebun
bun add @hey-api/openapi-python -DVersioning
This package is in initial development. Please pin an exact version so you can safely upgrade when you're ready.
We publish migration notes for every breaking release. You might not be impacted by a breaking change if you don't use the affected features.
Usage
CLI
Most people run @hey-api/openapi-python via CLI. To do that, add a script to your package.json file which will make openapi-python executable through script.
"scripts": {
"openapi-python": "openapi-python"
}The above script can be executed by running npm run openapi-python or equivalent command in other package managers. Next, we will create a configuration file and move our options from Quick Start to it.
Node.js
You can also generate output programmatically by calling createClient() in a JavaScript/TypeScript file.
`script.ts`
import { createClient } from '@hey-api/openapi-python';
createClient({
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
});Configuration
@hey-api/openapi-python supports loading configuration from any file inside your project root folder supported by jiti loader. Below are the most common file formats.
`openapi-python.config.ts`
import { defineConfig } from '@hey-api/openapi-python';
export default defineConfig({
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
});`openapi-python.config.cjs`
/** @type {import('@hey-api/openapi-python').UserConfig} */
module.exports = {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
};`openapi-python.config.mjs`
/** @type {import('@hey-api/openapi-python').UserConfig} */
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
};Alternatively, you can use openapi-python.config.js and configure the export statement depending on your project setup.
Input
You must set the input so we can load your OpenAPI specification. It can be a path or URL, object containing a path or URL, or an object representing an OpenAPI specification. Hey API supports all valid OpenAPI versions and file formats.
If you use an HTTPS URL with a self-signed certificate in development, you will need to set
NODE_TLS_REJECT_UNAUTHORIZED=0in your environment.
Output
You must set the output so we know where to generate your files. It can be a path to the destination folder or an object containing the destination folder path and optional settings.
You should treat the output folder as a dependency. Do not directly modify its contents as your changes might be erased when you run
@hey-api/openapi-pythonagain.
Parser
We parse your input before making it available to plugins. While configuring the parser is optional, it's the perfect place to modify or validate your input if needed.
Plugins
Plugins are responsible for generating artifacts from your input. By default, Hey API will generate Pydantic models and SDK from your OpenAPI specification. You can add, remove, or customize any of the plugins. In fact, we highly encourage you to do so!
Client
Clients are responsible for sending the actual HTTP requests. We default to HTTPX client if you're generating SDKs, but you can choose a different option from the available clients.
Available Clients
Proposed Clients (Vote to Prioritize)
The following clients are roadmap proposals and are not started yet. You can help us prioritize them by voting on GitHub.
Don't see your client? Build your own or let us know your interest by opening an issue.
Available Plugins
These plugins help reduce boilerplate associated with third-party dependencies. Hey API natively supports the most popular packages. Please open an issue on GitHub if you'd like us to support your favorite package.
Proposed Plugins (Vote to Prioritize)
The following plugins are roadmap proposals and are not started yet. You can help us prioritize them by voting on GitHub.
Don't see your plugin? Build your own or let us know your interest by opening an issue.
Migrating
You can learn more on the Migrating page.
License
Released under the MIT License.
Overview (`packages/openapi-ts/README.md`)
About
The OpenAPI to TypeScript code generator used by Vercel, OpenCode, and PayPal.
Generate production-grade SDKs, Zod schemas, TanStack Query hooks, or choose from 20+ other plugins.
Part of the Hey API ecosystem.
Features
- production-grade code that compiles
- runs in any Node.js 22+ environment
- accepts any OpenAPI specification
- core plugins for SDKs, types, and schemas
- HTTP clients for Fetch API, Angular, Axios, Next.js, Nuxt, and more
- 20+ plugins to reduce third-party boilerplate
- highly customizable via plugins
- sync with Hey API Registry for spec management
Contributing
Want to see your code in products used by millions?
Start with our Contributing guide and release your first feature.
Sponsors
Partners behind the future of API tooling. Become a sponsor.
Gold
Silver
| fastapi.tiangolo.com | getunblocked.com |
|---|
Bronze
Quick Start
The fastest way to use @hey-api/openapi-ts is via npx
npx @hey-api/openapi-ts -i hey-api/backend -o src/clientCongratulations on creating your first client! 🎉 You can learn more about the generated files on the Output page.
Installation
You can download @hey-api/openapi-ts from npm using your favorite package manager.
npm
npm install @hey-api/openapi-ts -D -Epnpm
pnpm add @hey-api/openapi-ts -D -Eyarn
yarn add @hey-api/openapi-ts -D -Ebun
bun add @hey-api/openapi-ts -DVersioning
This package is in initial development. Please pin an exact version so you can safely upgrade when you're ready.
We publish migration notes for every breaking release. You might not be impacted by a breaking change if you don't use the affected features.
Usage
CLI
Most people run @hey-api/openapi-ts via CLI. To do that, add a script to your package.json file which will make openapi-ts executable through script.
"scripts": {
"openapi-ts": "openapi-ts"
}The above script can be executed by running npm run openapi-ts or equivalent command in other package managers. Next, we will create a configuration file and move our options from Quick Start to it.
Node.js
You can also generate output programmatically by calling createClient() in a JavaScript/TypeScript file.
`script.ts`
import { createClient } from '@hey-api/openapi-ts';
createClient({
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
});Vite
If you're using Vite, you can integrate @hey-api/openapi-ts directly into your build pipeline with @hey-api/vite-plugin. Install it alongside the main package:
npm
npm install @hey-api/vite-plugin -D -Epnpm
pnpm add @hey-api/vite-plugin -D -Eyarn
yarn add @hey-api/vite-plugin -D -Ebun
bun add @hey-api/vite-plugin -DThen add the plugin to your Vite configuration:
`vite.config.ts`
import { heyApiPlugin } from '@hey-api/vite-plugin';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [
heyApiPlugin({
config: {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
},
}),
],
});See the Vite page for full configuration options.
Configuration
@hey-api/openapi-ts supports loading configuration from any file inside your project root folder supported by jiti loader. Below are the most common file formats.
`openapi-ts.config.ts`
import { defineConfig } from '@hey-api/openapi-ts';
export default defineConfig({
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
});`openapi-ts.config.cjs`
/** @type {import('@hey-api/openapi-ts').UserConfig} */
module.exports = {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
};`openapi-ts.config.mjs`
/** @type {import('@hey-api/openapi-ts').UserConfig} */
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
};Alternatively, you can use openapi-ts.config.js and configure the export statement depending on your project setup.
Input
You must set the input so we can load your OpenAPI specification. It can be a path or URL, object containing a path or URL, or an object representing an OpenAPI specification. Hey API supports all valid OpenAPI versions and file formats.
If you use an HTTPS URL with a self-signed certificate in development, you will need to set
NODE_TLS_REJECT_UNAUTHORIZED=0in your environment.
Output
You must set the output so we know where to generate your files. It can be a path to the destination folder or an object containing the destination folder path and optional settings.
You should treat the output folder as a dependency. Do not directly modify its contents as your changes might be erased when you run
@hey-api/openapi-tsagain.
Parser
We parse your input before making it available to plugins. While configuring the parser is optional, it's the perfect place to modify or validate your input if needed.
Plugins
Plugins are responsible for generating artifacts from your input. By default, Hey API will generate TypeScript interfaces and SDK from your OpenAPI specification. You can add, remove, or customize any of the plugins. In fact, we highly encourage you to do so!
Client
Clients are responsible for sending the actual HTTP requests. We default to Fetch client if you're generating SDKs, but you can choose a different option from the available clients.
Available Clients
@hey-api/client-fetch@hey-api/client-angular@hey-api/client-axios@hey-api/client-ky@hey-api/client-next@hey-api/client-nuxt@hey-api/client-ofetch
Proposed Clients (Vote to Prioritize)
The following clients are roadmap proposals and are not started yet. You can help us prioritize them by voting on GitHub.
Don't see your client? Build your own or let us know your interest by opening an issue.
Available Plugins
These plugins help reduce boilerplate associated with third-party dependencies. Hey API natively supports the most popular packages. Please open an issue on GitHub if you'd like us to support your favorite package.
@angular/common@hey-api/schemas@hey-api/sdk@hey-api/transformers@hey-api/typescript@pinia/colada@tanstack/angular-query-experimental@tanstack/preact-query@tanstack/react-query@tanstack/solid-query@tanstack/svelte-query@tanstack/vue-queryfastifyorpcnestjsvalibotzod
Proposed Plugins (Vote to Prioritize)
The following plugins are roadmap proposals and are not started yet. You can help us prioritize them by voting on GitHub.
- Adonis
- Ajv
- Arktype
- Chance
- Elysia
- Express
- Faker
- Falso
- Hono
- Joi
- Koa
- MSW
- Nock
- Superstruct
- Supertest
- SWR
- TanStack Start
- TypeBox
- Yup
- Zustand
Don't see your plugin? Build your own or let us know your interest by opening an issue.
Migrating
You can learn more on the Migrating page.
License
Released under the MIT License.
Overview (`packages/spec-types/README.md`)
About
TypeScript definitions for OpenAPI and JSON Schema specifications with complete inline documentation.
Part of the Hey API ecosystem.
Features
- OpenAPI 2.0 (Swagger), 3.0, and 3.1 specifications
- JSON Schema Draft 4 and Draft 2020-12
- inline JSDoc on every property
- zero runtime footprint, types only
Contributing
Want to see your code in products used by millions?
Start with our Contributing guide and release your first feature.
Sponsors
Partners behind the future of API tooling. Become a sponsor.
Gold
Silver
| fastapi.tiangolo.com | getunblocked.com |
|---|
Bronze
Installation
You can download @hey-api/spec-types from npm using your favorite package manager.
npm
npm install @hey-api/spec-types -D -Epnpm
pnpm add @hey-api/spec-types -D -Eyarn
yarn add @hey-api/spec-types -D -Ebun
bun add @hey-api/spec-types -DUsage
OpenAPI
Hover over any property to see its definition from the specification.
import type { OpenAPIV3_1 } from '@hey-api/spec-types';
const doc = {
openapi: '3.1.2',
info: {
title: 'My OpenAPI document',
version: '1.0.0',
},
} satisfies OpenAPIV3_1.Document;JSON Schema
Full type coverage for Draft 4 and Draft 2020-12 schemas.
import type { JSONSchemaDraft2020_12 } from '@hey-api/spec-types';
const doc = {
properties: {
foo: {
type: 'string',
},
},
type: 'object',
} satisfies JSONSchemaDraft2020_12.Document;License
Released under the MIT License.
Overview (`packages/vite-plugin/README.md`)
About
Vite is a blazing fast frontend build tool powering the next generation of web applications.
The Vite plugin integrates @hey-api/openapi-ts into the Vite build pipeline, running automatically whenever Vite resolves its configuration – no separate script or manual step required.
Part of the Hey API ecosystem.
Features
- runs automatically as part of your Vite build
- reads your existing configuration (or accepts inline config)
- supports Vite 5, 6, 7, and 8
- sync with Hey API Registry for spec management
Contributing
Want to see your code in products used by millions?
Start with our Contributing guide and release your first feature.
Sponsors
Partners behind the future of API tooling. Become a sponsor.
Gold
Silver
| fastapi.tiangolo.com | getunblocked.com |
|---|
Bronze
Installation
You can download @hey-api/vite-plugin from npm using your favorite package manager.
npm
npm install @hey-api/vite-plugin -D -Epnpm
pnpm add @hey-api/vite-plugin -D -Eyarn
yarn add @hey-api/vite-plugin -D -Ebun
bun add @hey-api/vite-plugin -DUsage
Add the plugin to your vite.config.ts:
import { heyApiPlugin } from '@hey-api/vite-plugin';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [heyApiPlugin()],
});The plugin will automatically pick up your configuration file. You can also pass options inline using the config option:
import { heyApiPlugin } from '@hey-api/vite-plugin';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [
heyApiPlugin({
config: {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
},
}),
],
});License
Released under the MIT License.
Overview (`packages/openapi-python/pypi/README.md`)
Hey API
OpenAPI to Python code generator. Production-grade SDKs and Pydantic models. Built by Hey API.
Installation
uv
Install:
uv add hey-apiOr run without installing:
uvx hey-api --helppip
Install:
pip install hey-apiOr run without installing:
pipx run hey-apiUsage
hey-api --helpResources
Web Src Content Docs Index (`web/src/content/docs/index.mdx`)
title: OpenAPI to code in seconds. template: splash
import Page from '@/components/pages/codegen/page.astro';
Web Src Content Docs Sponsors (`web/src/content/docs/sponsors.mdx`)
title: Sponsors template: splash
import SponsorsPage from '@/components/pages/sponsors/page.astro';
Web Src Content Docs Codegen Openapi Python (`web/src/content/docs/codegen/openapi/python.mdx`)
title: OpenAPI to Python in seconds. template: splash
import Page from '@/components/pages/codegen/page.astro';
Web Src Content Docs Codegen Openapi Typescript (`web/src/content/docs/codegen/openapi/typescript.mdx`)
title: OpenAPI to TypeScript in seconds. template: splash
import Page from '@/components/pages/codegen/page.astro';
Web Src Content Docs Docs Openapi Python Configuration (`web/src/content/docs/docs/openapi/python/configuration.mdx`)
title: Configuration sidebar: label: Overview
import { FileTree, Tabs, TabItem } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';
import InputTabs from '@/components/code-groups/InputTabs.mdx';
import OutputTabs from '@/components/code-groups/OutputTabs.mdx';
import UserConfig from '@/components/UserConfig.astro';
Configuration
@hey-api/openapi-python supports loading configuration from any file inside your project root folder supported by jiti loader. Below are the most common file formats.
export default defineConfig({
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
});
</TabItem>
<TabItem label="openapi-python.config.cjs">
```js
/** @type {import('@hey-api/openapi-python').UserConfig} */
module.exports = {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
};Alternatively, you can use openapi-python.config.js and configure the export statement depending on your project setup.
Input
You must provide an input so we can load your OpenAPI specification.
The input can be a string path, URL, API registry shorthand, an object containing any of these, or an object representing an OpenAPI specification. Hey API supports all valid OpenAPI versions and file formats.
You can learn more on the Input page.
:::tip
If you use an HTTPS URL with a self-signed certificate in development, you will need to set NODE_TLS_REJECT_UNAUTHORIZED=0 in your environment.
:::
Output
You must set the output so we know where to generate your files. It can be a path to the destination folder or an object containing the destination folder path and optional settings.
You can learn more on the Output page.
:::tip
You should treat the output folder as a dependency. Do not directly modify its contents as your changes might be erased when you run @hey-api/openapi-python again.
:::
Parser
We parse your input before making it available to plugins. Configuring the parser is optional, but it provides an ideal opportunity to modify or validate your input as needed.
You can learn more on the Parser page.
Plugins
Plugins are responsible for generating artifacts from your input. By default, Hey API will generate Pydantic models and SDK from your OpenAPI specification. You can add, remove, or customize any of the plugins. In fact, we highly encourage you to do so!
You can learn more on the Output page.
Advanced
More complex configuration scenarios can be handled by providing an array of inputs, outputs, or configurations.
Multiple jobs
Throughout this documentation, we generally reference single job configurations. However, you can easily run multiple jobs by providing an array of configuration objects.
Job matrix
Reusing configuration across multiple jobs is possible by defining a job matrix. You can create a job matrix by providing input and output arrays of matching length.
Merging inputs
You can merge inputs by defining multiple inputs and a single output.
{/*
Web Src Content Docs Docs Openapi Python Get Started (`web/src/content/docs/docs/openapi/python/get-started.mdx`)
title: Get Started
import InstallCommand from '@/components/package-managers/InstallCommand.astro';
import Examples from '@/components/Examples.astro';
import StackBlitz from '@/components/StackBlitz.astro';
Get Started
@hey-api/openapi-python generates Python code from OpenAPI specifications. Point it at your spec, pick your plugins, and get production-grade code in seconds.
{/* Used by companies like Vercel, OpenCode, and PayPal. */}
“The ecosystem trusted by TypeScript developers is coming to Python codebases.”
— Lubos, Founder of Hey API
{/* ### Demo
<StackBlitz
example="hey-api-example"
openFile={[
'openapi-ts.config.ts',
'src/client/schemas.gen.ts',
'src/client/sdk.gen.ts',
'src/client/types.gen.ts',
]}
/> */}
Features
- production-grade code that compiles
- runs in any Node.js 22+ environment
- accepts any OpenAPI specification
- core plugin for SDKs
- HTTP client for HTTPX
- highly customizable via plugins
- sync with Hey API Registry for spec management
{/* - 20+ plugins to reduce third-party boilerplate */}
Quick Start
The fastest way to use @hey-api/openapi-python is via npx
npx @hey-api/openapi-python -i hey-api/backend -o src/clientCongratulations on creating your first client! 🎉 You can learn more about the generated files on the Output page.
Installation
You can download @hey-api/openapi-python from npm using your favorite package manager.
Versioning
This package is in initial development. Please pin an exact version so you can safely upgrade when you're ready.
We publish migration notes for every breaking release. You might not be impacted by a breaking change if you don't use the affected features.
Usage
CLI
Most people run @hey-api/openapi-python via CLI. To do that, add a script to your package.json file which will make openapi-python executable through script.
"scripts": {
"openapi-python": "openapi-python"
}The above script can be executed by running npm run openapi-python or equivalent command in other package managers. Next, we will create a configuration file and move our options from Quick Start to it.
Node.js
You can also generate output programmatically by calling createClient() in a JavaScript/TypeScript file.
import { createClient } from '@hey-api/openapi-python';
createClient({
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
});{/* ### Vite
If you're using Vite 5, 6, 7, or 8, you can integrate @hey-api/openapi-python directly into your build pipeline with @hey-api/vite-plugin. Install it alongside the main package:
Then add the plugin to your Vite configuration:
import { heyApiPlugin } from '@hey-api/vite-plugin';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [
heyApiPlugin({
config: {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
},
}),
],
});See the Vite page for full configuration options. */}
Configuration
It's a good practice to extract your configuration into a separate file. Learn how to do that and discover available options on the Configuration page.
{/*
Web Src Content Docs Docs Openapi Python Migrating (`web/src/content/docs/docs/openapi/python/migrating.mdx`)
title: Migrating
import { Tabs, TabItem } from '@astrojs/starlight/components';
Migrating
Hey API is in active development, which allows us to move quickly and continuously improve the project. That pace sometimes comes with breaking changes. This page documents those changes and provides migration guidance for each release. If you need help with a migration, please open an issue.
v0.1.0
Coming soon.
Web Src Content Docs Docs Openapi Python Output (`web/src/content/docs/docs/openapi/python/output.mdx`)
title: Output
import { FileTree, Tabs, TabItem } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';
Output
Every generated file in your output folder is created by a plugin. This page describes the default output, but similar logic applies to all plugins.
Overview
If you use the default configuration, your project might look like this.
Your actual output depends on your Hey API configuration. It may contain a different number of files and their contents might differ.
Let's go through each file in the src/client folder and explain what it looks like, what it does, and how to use it.
Client
client.gen.ts is generated by client plugins. If you choose to generate SDKs (enabled by default), we use the Fetch client unless specified otherwise.
import { createClient, createConfig } from './client';
export const client = createClient(createConfig());The contents of this file are consumed by SDKs, but you can also import client in your application to perform additional configuration or send manual requests.
Bundle
Client plugins provide their bundles inside client and core folders. The contents of these folders don't depend on the provided input. Everything inside these folders serves as a scaffolding so the generated code can make HTTP requests.
TypeScript
You can learn more on the TypeScript page.
SDK
You can learn more on the SDK page.
Entry File
index.ts is not generated by any specific plugin. It's meant for convenience and by default, it re-exports every artifact generated by default plugins (TypeScript and SDK).
export * from './sdk.gen';
export * from './types.gen';Disable entry file
We recommend importing artifacts from their respective files to avoid ambiguity, but we leave this choice up to you.
import type { Pet } from './client';
// or
import type { Pet } from './client/types.gen';If you're not importing artifacts from the entry file, you can skip generating it altogether by setting the output.entryFile option to false.
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: {
entryFile: false,
path: 'src/client',
},
};Re-export artifacts
You can choose which artifacts should be re-exported from the entry file using the includeInEntry option on any plugin. For example, we can re-export all Zod plugin artifacts by setting includeInEntry to true:
Or we can re-export only specific artifacts by providing a predicate function:
Web Src Content Docs Docs Openapi Typescript Clients (`web/src/content/docs/docs/openapi/typescript/clients.mdx`)
title: Clients sidebar: label: Overview
import { Badge } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';
HTTP Clients
We all send HTTP requests in a slightly different way. Hey API doesn't force you to use any specific technology. What we do, however, is support your choice with great clients. All seamlessly integrated with our other features.
Features
- seamless integration with
@hey-api/openapi-tsecosystem - type-safe response data and errors
- response data validation and transformation
- access to the original request and response
- granular request and response customization options
- minimal learning curve thanks to extending the underlying technology
- support bundling inside the generated output
Plugins
Hey API natively supports the following clients.
Don't see your client? Build your own or let us know your interest by opening an issue.
Web Src Content Docs Docs Openapi Typescript Configuration (`web/src/content/docs/docs/openapi/typescript/configuration.mdx`)
title: Configuration sidebar: label: Overview
import { FileTree, Tabs, TabItem } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';
import InputTabs from '@/components/code-groups/InputTabs.mdx';
import OutputTabs from '@/components/code-groups/OutputTabs.mdx';
import UserConfig from '@/components/UserConfig.astro';
Configuration
@hey-api/openapi-ts supports loading configuration from any file inside your project root folder supported by jiti loader. Below are the most common file formats.
export default defineConfig({
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
});
</TabItem>
<TabItem label="openapi-ts.config.cjs">
```js
/** @type {import('@hey-api/openapi-ts').UserConfig} */
module.exports = {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
};Alternatively, you can use openapi-ts.config.js and configure the export statement depending on your project setup.
Input
You must provide an input so we can load your OpenAPI specification.
The input can be a string path, URL, API registry shorthand, an object containing any of these, or an object representing an OpenAPI specification. Hey API supports all valid OpenAPI versions and file formats.
You can learn more on the Input page.
:::tip
If you use an HTTPS URL with a self-signed certificate in development, you will need to set NODE_TLS_REJECT_UNAUTHORIZED=0 in your environment.
:::
Output
You must set the output so we know where to generate your files. It can be a path to the destination folder or an object containing the destination folder path and optional settings.
You can learn more on the Output page.
:::tip
You should treat the output folder as a dependency. Do not directly modify its contents as your changes might be erased when you run @hey-api/openapi-ts again.
:::
Parser
We parse your input before making it available to plugins. Configuring the parser is optional, but it provides an ideal opportunity to modify or validate your input as needed.
You can learn more on the Parser page.
Plugins
Plugins are responsible for generating artifacts from your input. By default, Hey API will generate TypeScript interfaces and SDK from your OpenAPI specification. You can add, remove, or customize any of the plugins. In fact, we highly encourage you to do so!
You can learn more on the Output page.
Advanced
More complex configuration scenarios can be handled by providing an array of inputs, outputs, or configurations.
Multiple jobs
Throughout this documentation, we generally reference single job configurations. However, you can easily run multiple jobs by providing an array of configuration objects.
Job matrix
Reusing configuration across multiple jobs is possible by defining a job matrix. You can create a job matrix by providing input and output arrays of matching length.
Merging inputs
You can merge inputs by defining multiple inputs and a single output.
Web Src Content Docs Docs Openapi Typescript Core (`web/src/content/docs/docs/openapi/typescript/core.mdx`)
title: Core Plugins sidebar: label: Overview
import Examples from '@/components/Examples.astro';
Core
Apart from being responsible for the default output, core plugins are the foundation for other plugins. Instead of creating their own primitives, other plugins can reuse the artifacts from core plugins. This results in a smaller output size and a better user experience.
Plugins
Hey API provides the following core plugins.
Need another core plugin? Let us know by opening an issue.
Web Src Content Docs Docs Openapi Typescript Get Started (`web/src/content/docs/docs/openapi/typescript/get-started.mdx`)
title: Get Started
import InstallCommand from '@/components/package-managers/InstallCommand.astro';
import Examples from '@/components/Examples.astro';
import StackBlitz from '@/components/StackBlitz.astro';
Get Started
@hey-api/openapi-ts generates TypeScript code from OpenAPI specifications. Point it at your spec, pick your plugins, and get production-grade code in seconds.
Used by companies like Vercel, OpenCode, and PayPal.
“OpenAPI codegen that just works.”
— Guillermo Rauch, CEO of Vercel
Demo
<StackBlitz
example="hey-api-example"
openFile={[
'openapi-ts.config.ts',
'src/client/schemas.gen.ts',
'src/client/sdk.gen.ts',
'src/client/types.gen.ts',
]}
/>
Features
- production-grade code that compiles
- runs in any Node.js 22+ environment
- accepts any OpenAPI specification
- core plugins for SDKs, types, and schemas
- HTTP clients for Fetch API, Angular, Axios, Next.js, Nuxt, and more
- 20+ plugins to reduce third-party boilerplate
- highly customizable via plugins
- sync with Hey API Registry for spec management
Quick Start
The fastest way to use @hey-api/openapi-ts is via npx
npx @hey-api/openapi-ts -i hey-api/backend -o src/clientCongratulations on creating your first client! 🎉 You can learn more about the generated files on the Output page.
Installation
You can download @hey-api/openapi-ts from npm using your favorite package manager.
Versioning
This package is in initial development. Please pin an exact version so you can safely upgrade when you're ready.
We publish migration notes for every breaking release. You might not be impacted by a breaking change if you don't use the affected features.
Usage
CLI
Most people run @hey-api/openapi-ts via CLI. To do that, add a script to your package.json file which will make openapi-ts executable through script.
"scripts": {
"openapi-ts": "openapi-ts"
}The above script can be executed by running npm run openapi-ts or equivalent command in other package managers. Next, we will create a configuration file and move our options from Quick Start to it.
Node.js
You can also generate output programmatically by calling createClient() in a JavaScript/TypeScript file.
import { createClient } from '@hey-api/openapi-ts';
createClient({
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
});Vite
If you're using Vite 5, 6, 7, or 8, you can integrate @hey-api/openapi-ts directly into your build pipeline with @hey-api/vite-plugin. Install it alongside the main package:
Then add the plugin to your Vite configuration:
import { heyApiPlugin } from '@hey-api/vite-plugin';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [
heyApiPlugin({
config: {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
},
}),
],
});See the Vite page for full configuration options.
Configuration
It's a good practice to extract your configuration into a separate file. Learn how to do that and discover available options on the Configuration page.
Web Src Content Docs Docs Openapi Typescript Integrations (`web/src/content/docs/docs/openapi/typescript/integrations.mdx`)
title: Hey API Platform sidebar: label: GitHub
import { Code, Tabs, TabItem } from '@astrojs/starlight/components';
Hey API Platform
:::caution
This feature is in development! 🎉 Try it out and provide feedback on GitHub.
:::
You can automate your client generation with Hey API Platform thanks to reproducible builds. Create dependency links between your clients and APIs, and watch the magic unfold. It's completely language and codegen agnostic.
Features
- API version history
- real-time updates
- reproducible builds
- language and codegen agnostic (TypeScript/Python/Go/Java/etc codegens are welcome)
Upload Specifications
Before you can generate clients, you must publish your OpenAPI specifications to Hey API.
Prerequisites
- Create a free account with Hey API.
- Create a new organization and project for your API provider. We recommend your naming matches your GitHub structure as it will be referenced by API clients. For example, we are using hey-api/backend for the platform.
- Inside your project, go to Integrations > APIs and generate an API key. Keep this value secret, it will be used to upload files.
Add GitHub CI workflow
Once you have your API key, you can start uploading OpenAPI specifications on every API build. We'll use our GitHub Action, but you can also make the API call manually if you're not using GitHub.
Create a new GitHub workflow or add an upload step to an existing workflow inside your API codebase. The example below will upload your OpenAPI specification to Hey API on every pull request and push to the main branch.
name: Upload OpenAPI Specification
on:
push:
branches:
- main
pull_request:
jobs:
upload-openapi-spec:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Upload OpenAPI spec
uses: hey-api/[email protected]
with:
path-to-file: path/to/openapi.json
tags: optional,custom,tags
env:
API_KEY: ${{ secrets.HEY_API_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}Inputs
To successfully upload an OpenAPI specification, you need to provide the following inputs (see with in the example above)
`path-to-file`
A relative path to your OpenAPI file within the repository. Note that you might need an additional step in your GitHub workflow to generate this file (see FastAPI example).
`tags` (optional)
A comma-separated string value representing any custom tags you wish to add to your OpenAPI specification.
Environment Variables
In addition to the required path-to-file input, you must provide the following environment variables.
`API_KEY`
This is the project API key you obtained from Hey API.
:::caution
Personal API keys can't be used to upload specifications.
:::
`GITHUB_TOKEN`
This variable will be available inside your workflow by default. It's used to
fetch information about your repository, i.e., default branch.
Generate Clients
You can generate clients from public projects or any private projects you can access. The setup is largely the same, you want to configure the input path used by your codegen.
By default, we preserve the current behavior and return the latest specification. Let's have a closer look at the input path and change that.
Get API
As you can deduce from the examples above, the default command for fetching OpenAPI specifications looks like this.
https://get.heyapi.dev/<organization>/<project>If you created an organization foo with project bar earlier, your URL would look like this.
https://get.heyapi.dev/foo/barAuth
Projects are private by default, you will need to be authenticated to download OpenAPI specifications. We recommend using project API keys in CI workflows and personal API keys for local development.
Once you have your API key, you can authenticate the request using the Authorization header or api_key query parameter.
https://get.heyapi.dev/foo/bar?api_key=<my_api_key>Congratulations on fetching your first OpenAPI specification! 🎉
Filters
The default behavior returns the last uploaded specification. This might not be what you want. You can use a range of filters to narrow down the possible specifications, or pin your builds to an exact version.
`branch`
You can fetch the last build from branch by providing the branch query parameter.
https://get.heyapi.dev/foo/bar?branch=production`commit_sha`
You can fetch an exact specification by providing the commit_sha query parameter. This will always return the same file.
https://get.heyapi.dev/foo/bar?commit_sha=0eb34c2024841ce95620f3ec02a2fea164ea4e9d`tags`
If you're tagging your specifications with custom tags, you can use them to filter the results. When you provide multiple tags, only the first match will be returned.
https://get.heyapi.dev/foo/bar?tags=optional,custom,tags`version`
Every OpenAPI document contains a required version field. You can use this value to fetch the last uploaded specification matching the value.
https://get.heyapi.dev/foo/bar?version=1.0.0Feedback
We'd love your feedback! You can contact us on social media (search Hey API), email, or GitHub.
Pricing
The platform is currently in beta with our focus being on delivering a great experience. We plan to announce pricing once we have gathered enough data around usage patterns. However, we can guarantee there will always be a free plan available. Our mission to bring the finest tooling for working with APIs remains unchanged.
Web Src Content Docs Docs Openapi Typescript License (`web/src/content/docs/docs/openapi/typescript/license.md`)
title: License
License
MIT License
Copyright (c) 2026-present Hey API
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Web Src Content Docs Docs Openapi Typescript Migrating (`web/src/content/docs/docs/openapi/typescript/migrating.mdx`)
title: Migrating
import { Tabs, TabItem } from '@astrojs/starlight/components';
Migrating
Hey API is in active development, which allows us to move quickly and continuously improve the project. That pace sometimes comes with breaking changes. This page documents those changes and provides migration guidance for each release. If you need help with a migration, please open an issue.
v0.99.0
Plugin duplicates behavior
If you specified the same plugin multiple times, only the last instance would be used. We eventually added a warning for this behavior, but that didn't treat the root issue. This release changes that by merging duplicate plugin configurations.
Renamed `plugin.symbols` to `plugin.imports`
To better represent its functionality, the plugin.symbols property has been renamed to plugin.imports.
Removed `plugin.external()` function
This function was used to reference external symbols. All plugins now use the Imports API, which allows you to reference external symbols in a type-safe way through plugin.imports.
Removed `plugin.registerSymbol()` function
This function was an alias for plugin.symbol() accepting a single argument. It has been removed in favor of plugin.symbol() which can now also accept a single argument.
v0.98.0
Declarative configuration
This is an internal change that simplifies the configuration and plugin APIs. The generated output should be unaffected, please open an issue if that's not the case. If you have custom plugins, refer to the custom plugin guide for the latest instructions.
v0.97.0
Changed `runtimeConfigPath` behavior
This was a known, long-standing issue confusing first-time users. Before, defining client runtimeConfigPath value would paste it verbatim to the generated output. This release changes the behavior to resolve relative to the output folder.
Changed Ky client behavior
The Ky client was updated to be more intuitive. Some Ky options now need to be passed via the kyOptions field and you need to pass undefined to unset an option.
Changed error interceptors behavior
Error interceptors now receive the result of the previous error interceptor. This aligns their behavior with request and response interceptors. This change only affects you if you use multiple interceptors.
Optional client request and response
The returned request and response objects are now typed as optional. This aligns the types with the actual runtime behavior, which remains unchanged.
Respect `throwOnError` option
Previously, there were instances where setting throwOnError to false would still throw an error. This most commonly happened when request validation failed. With this change, throwOnError is now truly respected.
v0.96.0
Removed Node 20 support
This release bumps the minimum required Node version to 22.13.
v0.95.0
Validator request schemas
Valibot and Zod plugins no longer export composite request Data schemas. Instead, each layer is exported as a separate schema. If you're using validators with SDKs, you can preserve the composite schema with shouldExtract:
Removed `plugin.getSymbol()` function
This function has been removed. You can use plugin.querySymbol() instead. It accepts the same arguments and returns the same result.
v0.93.0
Removed resolver node
Valibot and Zod plugins no longer expose the enum.nodes.nullable node. Both plugins were refactored so that nullable values are handled outside of resolvers.
v0.92.0
Updated Symbol interface
The exportFrom property has been replaced with the getExportFromFilePath() function. This allows you to dynamically determine export paths based on symbol properties. This is a low-level feature, so you're most likely unaffected.
v0.91.0
Removed CommonJS (CJS) support
@hey-api/openapi-ts is now ESM-only. This change simplifies the codebase, improves tree-shaking, and enables better integration with modern bundlers and TypeScript tooling.
CommonJS entry points (require(), module.exports) are no longer supported. If you are in a CJS environment, you can still load the package dynamically using import() like:
const { defineConfig } = await import('@hey-api/openapi-ts');If you have previously written:
const { defineConfig } = require('@hey-api/openapi-ts');Migrate by updating your static imports:
import { defineConfig } from '@hey-api/openapi-ts';If your environment cannot use ESM, pin to a previous version.
v0.90.0
Resolvers API
The Resolvers API has been simplified and expanded to provide a more consistent behavior across plugins. You can view a few common examples on the Resolvers page.
Structure API
The SDK plugin and Angular plugin now implement the Structure API, enabling more complex structures and fixing several known issues.
Some Structure APIs are incompatible with the previous configuration, most notably the methodNameBuilder function, which accepted the operation object as an argument. You can read the SDK Output section to familiarize yourself with the Structure API.
Please open an issue if you're unable to migrate your configuration to the new syntax.
v0.89.0
Prefer named exports
This release changes the default for index.ts to prefer named exports. Named exports may lead to better IDE and bundler performance compared to asterisk (*) as your tooling doesn't have to inspect the underlying module to discover exports.
While this change is merely cosmetic, you can set output.preferExportAll to true if you prefer to use the asterisk.
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: {
path: 'src/client',
preferExportAll: true,
},
};Removed `symbol:setValue:*` events
These events have been removed in favor of node:set:* events.
v0.88.0
Removed `compiler` and `tsc` exports
This release removes the compiler utility functions. Instead, it introduces a new TypeScript DSL exposed under the $ symbol. All plugins now use this interface, so you may notice slight changes in the generated output.
v0.87.0
Removed legacy clients
This release removes support for legacy clients and plugins. Please migrate to the new clients if you haven't done so yet. If you're unable to do so due to a missing feature, let us know on GitHub.
v0.86.0
Removed Node 18 support
This release bumps the minimum required Node version to 20.19.
v0.85.0
Updated `output` options
We made the output configuration more consistent by using null to represent disabled options. This change does not affect boolean options.
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: {
format: false,
format: null,
lint: false,
lint: null,
path: 'src/client',
tsConfigPath: 'off',
tsConfigPath: null,
},
};Updated Pinia Colada query options
Pinia Colada query options now use defineQueryOptions to improve reactivity support. Instead of calling the query options function, you can use one of the following approaches.
useQuery(getPetByIdQuery, () => ({
path: {
petId: petId.value,
},
}));
</TabItem>
<TabItem label="properties">
```ts title="colada.gen.ts"
const petId = ref<number | null>(1);
useQuery(() => ({
...getPetByIdQuery({
path: { petId: petId.value as number },
}),
enabled: () => petId.value !== null,
}));v0.84.0
Symbol API
This release improves the Symbol API, which adds the capability to place symbols in arbitrary files. We preserved the previous output structure for all plugins except Angular.
You can preserve the previous Angular output by writing your own placement function.
TypeScript renderer
We ship a dedicated TypeScript renderer for .ts files. This release improves the renderer's ability to group and sort imported modules, resulting in a more polished output.
Removed `output` plugin option
Due to the Symbol API release, this option has been removed from the Plugin API.
v0.83.0
Symbol API
This release adds the Symbol API, which significantly reduces the risk of naming collisions. While the generated output should only include formatting changes, this feature introduces breaking changes to the Plugin API that affect custom plugins.
We will update the custom plugin guide once the Plugin API becomes more stable.
Removed `groupByTag` Pinia Colada option
This option has been removed to provide a more consistent API across plugins. We plan to bring it back in a future release.
v0.82.0
Hooks API
This release adds the Hooks API, giving you granular control over which operations generate queries and mutations. As a result, we tightened the previous behavior and POST operations no longer generate queries by default. To preserve the old behavior, add a custom matcher.
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
parser: {
hooks: {
operations: {
isQuery: (op) => (op.method === 'post' ? true : undefined),
},
},
},
};v0.81.0
Server-Sent Events (SSE)
This release adds support for server-sent events (SSE). Instead of treating text/event-stream content types as regular HTTP methods, we now generate SSE streams. In practice, you will want to update your affected endpoints to process streamed events.
v0.80.0
Added Zod 4 and Zod Mini
This release adds support for Zod 4 and Zod Mini. By default, the zod plugin will generate output for Zod 4. If you want to preserve the previous output for Zod 3 or use Zod Mini, set compatibilityVersion to 3 or mini.
v0.79.0
Removed `typescript+namespace` enums mode
Due to a simpler TypeScript plugin implementation, the typescript+namespace enums mode is no longer necessary. This mode was used in the past to group inline enums under the same namespace. With the latest changes, this behavior is no longer supported. You can either choose to ignore inline enums (default), or use the enums transform (added in v0.78.0) to convert them into reusable components which will get exported as usual.
v0.78.0
Added `parser` options
Previously, @hey-api/typescript would generate correct types, but the validator plugins would have to re-implement the same logic or generate schemas that didn't match the generated types.
Since neither option was ideal, this release adds a dedicated place for parser options. Parser is responsible for preparing the input so plugins can generate more accurate output with less effort.
You can learn more about configuring parser on the Parser page.
Moved `input` options
The following options were moved to the new parser group.
input.filtersmoved toparser.filtersinput.paginationmoved toparser.paginationinput.patchmoved toparser.patchinput.validate_EXPERIMENTALmoved toparser.validate_EXPERIMENTAL
Updated `typescript` options
The following options were renamed.
enumsCasemoved toenums.caseenumsConstantsIgnoreNullmoved toenums.constantsIgnoreNull
Moved `typescript` options
The following options were moved to the new parser group.
exportInlineEnumsmoved toparser.transforms.enumsreadOnlyWriteOnlyBehaviormoved toparser.transforms.readWrite.enabledreadableNameBuildermoved toparser.transforms.readWrite.responses.namewritableNameBuildermoved toparser.transforms.readWrite.requests.name
Updated `readWrite.responses` name
Additionally, the naming pattern for response schemas has changed from {name}Readable to {name}. This is to prevent your code from breaking by default when using a schema that gets updated with a write-only field.
v0.77.0
Updated `sdk.validator` option
Clients can now validate both request and response data. As a result, passing a boolean or string to validator will control both of these options. To preserve the previous behavior, set validator.request to false and validator.response to your previous configuration.
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
{
name: '@hey-api/sdk',
validator: true,
validator: {
request: false,
response: true,
},
},
],
};Updated Plugin API
Please refer to the custom plugin tutorial for the latest guide.
v0.76.0
Single Valibot schema per request
Previously, we generated a separate schema for each endpoint parameter and request body. In v0.76.0, a single request schema is generated for the whole endpoint. It may contain a request body, parameters, and headers.
const vData = v.object({
body: v.optional(
v.object({
foo: v.optional(v.string()),
bar: v.optional(v.union([v.number(), v.null()])),
}),
),
headers: v.optional(v.never()),
path: v.object({
baz: v.string(),
}),
query: v.optional(v.never()),
});If you need to access individual fields, you can do so using the .entries API. For example, we can get the request body schema with vData.entries.body.
v0.75.0
Updated TanStack Query options
The TanStack Query plugin options have been expanded to support more naming and casing patterns. As a result, the following options have been renamed.
queryOptionsNameBuilderrenamed toqueryOptionsinfiniteQueryOptionsNameBuilderrenamed toinfiniteQueryOptionsmutationOptionsNameBuilderrenamed tomutationOptionsqueryKeyNameBuilderrenamed toqueryKeysinfiniteQueryKeyNameBuilderrenamed toinfiniteQueryKeys
Added `plugin.forEach()` method
This method replaces the .subscribe() method. Additionally, .forEach() is executed immediately, which means we don't need the before and after events – simply move your code before and after the .forEach() block.
plugin.subscribe('operation', (event) => {
// do something with event
});
plugin.subscribe('schema', (event) => {
plugin.forEach('operation', 'schema', (event) => {
// do something with event
});v0.74.0
Single Zod schema per request
Previously, we generated a separate schema for each endpoint parameter and request body. In v0.74.0, a single request schema is generated for the whole endpoint. It may contain a request body, parameters, and headers.
const zData = z.object({
body: z
.object({
foo: z.string().optional(),
bar: z.union([z.number(), z.null()]).optional(),
})
.optional(),
headers: z.never().optional(),
path: z.object({
baz: z.string(),
}),
query: z.never().optional(),
});If you need to access individual fields, you can do so using the .shape API. For example, we can get the request body schema with zData.shape.body.
v0.73.0
Bundle `@hey-api/client-*` plugins
In previous releases, you had to install a separate client package to generate a fully working output, e.g., npm install @hey-api/client-fetch. This created a few challenges: getting started was slower, upgrading was sometimes painful, and bundling too. Beginning with v0.73.0, all Hey API clients are bundled by default and don't require installing any additional dependencies. You can remove any installed client packages and re-run @hey-api/openapi-ts.
npm uninstall @hey-api/client-fetchv0.72.0
Added `sdk.classStructure` option
When generating class-based SDKs, we now try to infer the ideal structure using operationId keywords. If you'd like to preserve the previous behavior, set classStructure to off.
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
{
classStructure: 'off',
name: '@hey-api/sdk',
},
],
};v0.71.0
Renamed `sdk.serviceNameBuilder` option
This option has been renamed to sdk.classNameBuilder to better represent its functionality. Additionally, it's no longer set by default. To preserve the previous behavior, update your configuration.
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
{
classNameBuilder: '{{name}}Service',
name: '@hey-api/sdk',
serviceNameBuilder: '{{name}}Service',
},
],
};v0.68.0
Upgraded input filters
Input filters now avoid generating invalid output without requiring you to specify every missing schema as in the previous releases. As part of this release, we changed the way filters are configured and removed the support for regular expressions. Let us know if regular expressions are still useful for you and want to bring them back!
v0.67.0
Respecting `moduleResolution` value in `tsconfig.json`
This release introduces functionality related to your tsconfig.json file. The initial feature properly respects the value of your moduleResolution field. If you're using nodenext, the relative module paths in your output will be appended with .js. To preserve the previous behavior where we never appended .js to relative module paths, set output.tsConfigPath to off.
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: {
path: 'src/client',
tsConfigPath: 'off',
},
};v0.66.0
Read-only and write-only fields
Starting with v0.66.0, @hey-api/typescript will generate separate types for payloads and responses if it detects any read-only or write-only fields. To preserve the previous behavior and generate a single type regardless, set readOnlyWriteOnlyBehavior to off.
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
{
name: '@hey-api/typescript',
readOnlyWriteOnlyBehavior: 'off',
},
],
};v0.64.0
Added `ClientOptions` interface
The Config interface now accepts an optional generic extending ClientOptions instead of boolean type ThrowOnError.
type Foo = Config<false>;
type Foo = Config<{ throwOnError: false }>;Added `client.baseUrl` option
You can use this option to configure the default base URL for the generated client. By default, we will attempt to resolve the first defined server or infer the base URL from the input path. If you'd like to preserve the previous behavior, set baseUrl to false.
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
{
baseUrl: false,
name: '@hey-api/client-fetch',
},
],
};v0.63.0
Client plugins
Clients are now plugins generating their own client.gen.ts file. There's no migration needed if you're using CLI. If you're using the configuration file, move client options to plugins.
export default {
client: '@hey-api/client-fetch',
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: ['@hey-api/client-fetch'],
};Added `client.gen.ts` file
Related to above, the internal client instance previously located in sdk.gen.ts is now defined in client.gen.ts. If you're importing it in your code, update the import module.
import { client } from 'client/sdk.gen';
import { client } from 'client/client.gen';Moved `sdk.throwOnError` option
This SDK configuration option has been moved to the client plugins where applicable. Not every client can be configured to throw on error, so it didn't make sense to expose the option when it didn't have any effect.
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
{
name: '@hey-api/client-fetch',
throwOnError: true,
},
{
name: '@hey-api/sdk',
throwOnError: true,
},
],
};v0.62.0
Changed parser
Formerly known as the experimental parser, this is now the default parser. This change should not impact the generated output's functionality. However, there might be cases where this results in breaking changes due to different handling of certain scenarios. If you need to revert to the legacy parser, set the experimentalParser flag to false.
export default {
client: '@hey-api/client-fetch',
experimentalParser: false,
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
};Note that the legacy parser is no longer supported and will be removed in the v1 release.
v0.61.0
Added `auth` option
Client package functions accessToken and apiKey were replaced with a single auth function for fetching auth tokens. If your API supports multiple auth mechanisms, you can use the auth argument to return the appropriate token.
import { client } from 'client/sdk.gen';
client.setConfig({
accessToken: () => '<my_token>',
apiKey: () => '<my_token>',
auth: (auth) => '<my_token>',
});Due to conflict with the Axios native auth option, we removed support for configuring Axios auth. Please let us know if you require this feature added back.
Added `watch` option
While this is a new feature, supporting it involved replacing the @apidevtools/json-schema-ref-parser dependency with our own implementation. Since this was a big change, we're applying caution and marking this as a breaking change.
Changed `parseAs: 'auto'` behavior
The Fetch API client will return raw response body as ReadableStream when Content-Type response header is undefined and parseAs is auto.
v0.60.0
Added `sdk.transformer` option
When generating SDKs, you now have to specify transformer in order to modify response data. By default, adding @hey-api/transformers to your plugins will only produce additional output. To preserve the previous functionality, set sdk.transformer to true.
export default {
client: '@hey-api/client-fetch',
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
{
dates: true,
name: '@hey-api/transformers',
},
{
name: '@hey-api/sdk',
transformer: true,
},
],
};v0.59.0
Added `logs.level` option
You can now configure different log levels. As part of this feature, we had to introduce a breaking change by moving the debug option to logs.level. This will affect you if you're calling @hey-api/openapi-ts from Node.js (not CLI) or using the configuration file.
export default {
client: '@hey-api/client-fetch',
debug: true,
input: 'hey-api/backend', // sign up at app.heyapi.dev
logs: {
level: 'debug',
},
output: 'src/client',
};Updated default `plugins`
@hey-api/schemas has been removed from the default plugins. To continue using it, add it to your plugins array.
export default {
client: '@hey-api/client-fetch',
experimentalParser: true,
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
'@hey-api/schemas',
],
};v0.58.0
Removed `schemas.gen.ts` re-export
index.ts will no longer re-export schemas.gen.ts to reduce the chance of producing broken output. Please update your code to import from schemas.gen.ts directly.
import { mySchema } from 'client';
import { mySchema } from 'client/schemas.gen';Removed `transformers.gen.ts` re-export
index.ts will no longer re-export transformers.gen.ts to reduce the chance of producing broken output. Please update your code to import from transformers.gen.ts directly.
import { myTransformer } from 'client';
import { myTransformer } from 'client/transformers.gen';Added `output.clean` option
By default, the output.path folder will be emptied on every run. To preserve the previous behavior, set output.clean to false.
export default {
client: '@hey-api/client-fetch',
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: {
clean: false,
path: 'src/client',
},
};Added `typescript.identifierCase` option
This change affects only the experimental parser. By default, the generated TypeScript interfaces will follow the PascalCase naming convention. In the previous versions, we tried to preserve the original name as much as possible. To keep the previous behavior, set typescript.identifierCase to preserve.
export default {
client: '@hey-api/client-fetch',
experimentalParser: true,
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
{
identifierCase: 'preserve',
name: '@hey-api/typescript',
},
],
};v0.57.0
Renamed `@hey-api/services` plugin
This plugin has been renamed to @hey-api/sdk.
Changed `sdk.output` value
To align with the updated name, the @hey-api/sdk plugin will generate an sdk.gen.ts file. This will result in a breaking change if you're importing from services.gen.ts. Please update your imports to reflect this change.
import { client } from 'client/services.gen';
import { client } from 'client/sdk.gen';Renamed `@hey-api/types` plugin
This plugin has been renamed to @hey-api/typescript.
Added `typescript.exportInlineEnums` option
By default, inline enums (enums not defined as reusable components in the input file) will be generated only as inlined union types. You can set exportInlineEnums to true to treat inline enums as reusable components. When true, the exported enums will follow the style defined in enums.
This is a breaking change since in the previous versions, inline enums were always treated as reusable components. To preserve your current output, set exportInlineEnums to true. This feature works only with the experimental parser.
export default {
client: '@hey-api/client-fetch',
experimentalParser: true,
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
{
exportInlineEnums: true,
name: '@hey-api/typescript',
},
],
};v0.56.0
Deprecated `tree` in `@hey-api/types`
This config option is deprecated and will be removed when the experimental parser becomes the default.
v0.55.0
This release adds the ability to filter your OpenAPI specification before it's processed. This feature will be useful if you are working with a large specification and are interested in generating output only from a small subset.
This feature is available only in the experimental parser. In the future, this will become the default parser. To opt-in to the experimental parser, set the experimentalParser flag in your configuration to true.
Deprecated `include` in `@hey-api/types`
This config option is deprecated and will be removed when the experimental parser becomes the default.
Deprecated `filter` in `@hey-api/services`
This config option is deprecated and will be removed when the experimental parser becomes the default.
Added `input.include` option
This config option can be used to replace the deprecated options. It accepts a regular expression string matching against references within the bundled specification.
export default {
client: '@hey-api/client-fetch',
experimentalParser: true,
input: {
include: '^(#/components/schemas/foo|#/paths/api/v1/foo/get)$',
path: 'hey-api/backend', // sign up at app.heyapi.dev
},
output: 'src/client',
};The configuration above will process only the schema named foo and GET operation for the /api/v1/foo path.
v0.54.0
This release makes plugins first-class citizens. In order to achieve that, the following breaking changes were introduced.
Removed CLI options
The --types, --schemas, and --services CLI options have been removed. You can list which plugins you'd like to use explicitly by passing a list of plugins as --plugins
Removed `*.export` option
Previously, you could explicitly disable export of certain artifacts using the *.export option or its shorthand variant. These were both removed. You can now disable export of specific artifacts by manually defining an array of plugins and excluding the unwanted plugin.
Renamed `schemas.name` option
Each plugin definition contains a name field. This was conflicting with the schemas.name option. As a result, it has been renamed to nameBuilder.
export default {
client: '@hey-api/client-fetch',
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
schemas: {
name: (name) => `${name}Schema`,
},
plugins: [
// ...other plugins
{
nameBuilder: (name) => `${name}Schema`,
name: '@hey-api/schemas',
},
],
};Removed `services.include` shorthand option
Previously, you could use a string value as a shorthand for the services.include configuration option. You can now achieve the same result using the include option.
export default {
client: '@hey-api/client-fetch',
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
services: '^MySchema',
plugins: [
// ...other plugins
{
include: '^MySchema',
name: '@hey-api/services',
},
],
};Renamed `services.name` option
Each plugin definition contains a name field. This was conflicting with the services.name option. As a result, it has been renamed to serviceNameBuilder.
export default {
client: '@hey-api/client-fetch',
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
services: {
name: '{{name}}Service',
},
plugins: [
// ...other plugins
{
serviceNameBuilder: '{{name}}Service',
name: '@hey-api/services',
},
],
};Renamed `types.dates` option
Previously, you could set types.dates to a boolean or a string value, depending on whether you wanted to transform only type strings into dates, or runtime code too. Many people found these options confusing, so they have been simplified to a boolean and extracted into a separate @hey-api/transformers plugin.
export default {
client: '@hey-api/client-fetch',
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
types: {
dates: 'types+transform',
},
plugins: [
// ...other plugins
{
dates: true,
name: '@hey-api/transformers',
},
],
};Removed `types.include` shorthand option
Previously, you could use a string value as a shorthand for the types.include configuration option. You can now achieve the same result using the include option.
export default {
client: '@hey-api/client-fetch',
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
types: '^MySchema',
plugins: [
// ...other plugins
{
include: '^MySchema',
name: '@hey-api/types',
},
],
};Renamed `types.name` option
Each plugin definition contains a name field. This was conflicting with the types.name option. As a result, it has been renamed to style.
export default {
client: '@hey-api/client-fetch',
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
types: {
name: 'PascalCase',
},
plugins: [
// ...other plugins
{
name: '@hey-api/types',
style: 'PascalCase',
},
],
};v0.53.0
Changed schemas name pattern
Previously, generated schemas would have their definition names prefixed with $. This was problematic when using them with Svelte due to reserved keyword conflicts. The new naming pattern for schemas suffixes their definition names with Schema. You can continue using the previous pattern by setting the schemas.name configuration option.
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
schemas: {
name: (name) => `$${name}`,
},
};Renamed legacy clients
Legacy clients were renamed to signal they are deprecated more clearly. To continue using legacy clients, you will need to update your configuration and prefix them with legacy/.
v0.52.0
Removed internal `client` export
Previously, client packages would create a default client which you'd then import and configure.
import { client, createClient } from '@hey-api/client-fetch';
createClient({
baseUrl: 'https://example.com',
});
console.log(client.getConfig().baseUrl); // <-- 'https://example.com'This client instance was used internally by services unless overridden. Apart from running createClient() twice, people were confused about the meaning of global configuration option.
Starting with v0.52.0, client packages will not create a default client. Instead, services will define their own client. You can now achieve the same configuration by importing client from services and using the new setConfig() method.
import { client } from 'client/services.gen';
client.setConfig({
baseUrl: 'https://example.com',
});
console.log(client.getConfig().baseUrl); // <-- 'https://example.com'v0.51.0
Required `client` option
Client now has to be explicitly specified and @hey-api/openapi-ts will no longer generate a legacy Fetch API client by default. To preserve the previous default behavior, set the client option to fetch.
export default {
client: 'fetch',
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
};v0.48.0
Changed `methodNameBuilder()` signature
The services.methodNameBuilder() function now provides a single operation argument instead of multiple cherry-picked properties from it.
import { createClient } from '@hey-api/openapi-ts';
createClient({
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
services: {
methodNameBuilder: (service, name) => name,
methodNameBuilder: (operation) => operation.name,
},
});v0.46.0
Tree-shakeable services
By default, your services will now support tree-shaking. You can either use wildcard imports
import { DefaultService } from 'client/services.gen';
import * as DefaultService from 'client/services.gen';
DefaultService.foo(); // only import needs to be changedor update all references to service classes
import { DefaultService } from 'client/services.gen';
import { foo } from 'client/services.gen';
foo(); // all references need to be changedIf you want to preserve the old behavior, you can set the newly exposed services.asClass option to true.
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
services: {
asClass: true,
},
};v0.45.0
Removed `client` inference
@hey-api/openapi-ts will no longer infer which client you want to generate. By default, we will create a fetch client. If you want a different client, you can specify it using the client option.
export default {
client: 'axios',
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
};v0.44.0
Moved `format`
This config option has been moved. You can now configure formatter using the output.format option.
export default {
format: 'prettier',
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: {
format: 'prettier',
path: 'src/client',
},
};Moved `lint`
This config option has been moved. You can now configure linter using the output.lint option.
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
lint: 'eslint',
output: {
lint: 'eslint',
path: 'src/client',
},
};v0.43.0
Removed `enums.gen.ts`
This file has been removed. Instead, enums are exported from types.gen.ts. If you use imports from enums.gen.ts, you should be able to easily find and replace all instances.
import { Foo } from 'client/enums.gen';
import { Foo } from 'client/types.gen';Removed `Enum` postfix
Generated enum names are no longer postfixed with Enum. You can either alias your imports
import { FooEnum } from 'client/types.gen';
import { Foo as FooEnum } from 'client/types.gen';
console.log(FooEnum.value); // only import needs to be changedor update all references to enums
import { FooEnum } from 'client/types.gen';
import { Foo } from 'client/types.gen';
console.log(Foo.value); // all references need to be changedMoved `enums`
This config option has been moved. You can now configure enums using the types.enums option.
export default {
enums: 'javascript',
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
types: {
enums: 'javascript',
},
};v0.42.0
Changed `format`
This config option has changed. You now need to specify a value (biome or prettier) to format the output (default: false).
export default {
format: 'prettier',
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
}Changed `lint`
This config option has changed. You now need to specify a value (biome or eslint) to lint the output (default: false).
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
lint: 'eslint',
output: 'src/client',
}Moved `operationId`
This config option has been moved. You can now configure it using the services.operationId option.
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
services: {
operationId: true,
},
}v0.41.0
Removed `postfixServices`
This config option has been removed. You can now transform service names using the string pattern parameter.
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
services: {
name: 'myAwesome{{name}}Api',
},
}Removed `serviceResponse`
This config option has been removed. You can now configure service responses using the services.response option.
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
services: {
response: 'body',
},
}Removed `useDateType`
This config option has been removed. You can now configure date type using the types.dates option.
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
type: {
dates: true,
},
}v0.40.0
Renamed `models.gen.ts` file
models.gen.ts is now called types.gen.ts. If you use imports from models.gen.ts, you should be able to easily find and replace all instances.
import type { Model } from 'client/models.gen';
import type { Model } from 'client/types.gen';Renamed `exportModels`
This config option is now called types.
PascalCase for types
You can now choose to export types using the PascalCase naming convention.
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
types: {
name: 'PascalCase',
},
}Exported `enums.gen.ts` file
Enums are now re-exported from the main index.ts file.
v0.39.0
Single `enums.gen.ts` file
Enums are now exported from a separate file. If you use imports from models.ts, you can change them to enums.gen.ts.
import { Enum } from 'client/models';
import { Enum } from 'client/enums.gen';Renamed `models.ts` file
models.ts is now called models.gen.ts. If you use imports from models.ts, you should be able to easily find and replace all instances.
import type { Model } from 'client/models';
import type { Model } from 'client/models.gen';Renamed `schemas.ts` file
schemas.ts is now called schemas.gen.ts. If you use imports from schemas.ts, you should be able to easily find and replace all instances.
import { $Schema } from 'client/schemas';
import { $Schema } from 'client/schemas.gen';Renamed `services.ts` file
services.ts is now called services.gen.ts. If you use imports from services.ts, you should be able to easily find and replace all instances.
import { DefaultService } from 'client/services';
import { DefaultService } from 'client/services.gen';Deprecated exports from `index.ts`
Until this release, index.ts file exported all generated artifacts. Starting from this release, enums are no longer exported from index.ts. Models, schemas, and services will continue to be exported from index.ts to avoid a huge migration lift, but we recommend migrating to import groups per artifact type.
import { Enum, type Model, $Schema, DefaultService } from 'client';
import { Enum } from 'client/enums.gen';
import type { Model } from 'client/models.gen';
import { $Schema } from 'client/schemas.gen';
import { DefaultService } from 'client/services.gen';Prefer `unknown`
Types that cannot be determined will now be generated as unknown instead of any. To dismiss any errors, you can cast your variables back to any, but we recommend updating your code to work with unknown types.
const foo = bar as anyv0.38.0
Renamed `write`
This config option is now called dryRun (file) or --dry-run (CLI). To restore existing functionality, invert the value, ie. write: true is dryRun: false and write: false is dryRun: true.
v0.36.0
JSON Schema 2020-12
Schemas are exported directly from OpenAPI specification. This means your schemas might change depending on which OpenAPI version you're using. If this release caused a field to be removed, consult the JSON Schema documentation on how to obtain the same value from JSON Schema (e.g., required properties).
Renamed `exportSchemas`
This config option is now called schemas.
v0.35.0
Removed `postfixModels`
This config option has been removed.
v0.34.0
Single `services.ts` file
Services are now exported from a single file. If you used imports from individual service files, these will need to be updated to refer to the single services.ts file.
v0.31.1
Merged enums options
useLegacyEnums config option is now enums: 'typescript' and existing enums: true option is now enums: 'javascript'.
v0.31.0
Single `models.ts` file
TypeScript interfaces are now exported from a single file. If you used imports from individual model files, these will need to be updated to refer to the single models.ts file.
Single `schemas.ts` file
Schemas are now exported from a single file. If you used imports from individual schema files, these will need to be updated to refer to the single schemas.ts file.
v0.27.38
`useOptions: true`
By default, generated clients will use a single object argument to pass values to API calls. This is a significant change from the previous default of unspecified array of arguments. If migrating your application in one go isn't feasible, we recommend deprecating your old client and generating a new client.
import { DefaultService } from 'client/services'; // <-- old client with array arguments
import { DefaultService } from 'client_v2/services'; // <-- new client with options argumentThis way, you can gradually switch over to the new syntax as you update parts of your code. Once you've removed all instances of client imports, you can safely delete the old client folder and find and replace all client_v2 calls to client.
v0.27.36
`exportSchemas: true`
By default, we will create schemas from your OpenAPI specification. Use exportSchemas: false to preserve the old behavior.
v0.27.32
Renamed `Config` interface
This interface is now called UserConfig.
v0.27.29
Renamed `openapi` CLI command
This command is now called openapi-ts.
v0.27.26
Removed `indent`
This config option has been removed. Use a code formatter to modify the generated files code style according to your preferences.
v0.27.24
Removed `useUnionTypes`
This config option has been removed. Generated types will behave the same as useUnionTypes: true before.
OpenAPI TypeScript Codegen
@hey-api/openapi-ts was originally forked from Ferdi Koomen's openapi-typescript-codegen. Therefore, we want you to be able to migrate your projects. Migration should be relatively straightforward if you follow the release notes on this page. Start on v0.27.24 and scroll to the release you're migrating to.
Web Src Content Docs Docs Openapi Typescript Mocks (`web/src/content/docs/docs/openapi/typescript/mocks.mdx`)
title: Testing sidebar: label: Overview
import { Badge } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';
Testing
Testing is an important component of every robust development process. Generate realistic mock data, intercept requests at the network layer, or drive assertions against a running server, all from your specification.
Plugins
Hey API natively supports the following testing libraries.
Don't see your library? Let us know by opening an issue.
Web Src Content Docs Docs Openapi Typescript Output (`web/src/content/docs/docs/openapi/typescript/output.mdx`)
title: Output
import { FileTree, Tabs, TabItem } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';
Output
Every generated file in your output folder is created by a plugin. This page describes the default output, but similar logic applies to all plugins.
Overview
If you use the default configuration, your project might look like this.
Your actual output depends on your Hey API configuration. It may contain a different number of files and their contents might differ.
Let's go through each file in the src/client folder and explain what it looks like, what it does, and how to use it.
Client
client.gen.ts is generated by client plugins. If you choose to generate SDKs (enabled by default), we use the Fetch client unless specified otherwise.
import { createClient, createConfig } from './client';
export const client = createClient(createConfig());The contents of this file are consumed by SDKs, but you can also import client in your application to perform additional configuration or send manual requests.
Bundle
Client plugins provide their bundles inside client and core folders. The contents of these folders don't depend on the provided input. Everything inside these folders serves as a scaffolding so the generated code can make HTTP requests.
TypeScript
You can learn more on the TypeScript page.
SDK
You can learn more on the SDK page.
Entry File
index.ts is not generated by any specific plugin. It's meant for convenience and by default, it re-exports every artifact generated by default plugins (TypeScript and SDK).
export * from './sdk.gen';
export * from './types.gen';Disable entry file
We recommend importing artifacts from their respective files to avoid ambiguity, but we leave this choice up to you.
import type { Pet } from './client';
// or
import type { Pet } from './client/types.gen';If you're not importing artifacts from the entry file, you can skip generating it altogether by setting the output.entryFile option to false.
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: {
entryFile: false,
path: 'src/client',
},
};Re-export artifacts
You can choose which artifacts should be re-exported from the entry file using the includeInEntry option on any plugin. For example, we can re-export all Zod plugin artifacts by setting includeInEntry to true:
Or we can re-export only specific artifacts by providing a predicate function:
Web Src Content Docs Docs Openapi Typescript State Management (`web/src/content/docs/docs/openapi/typescript/state-management.mdx`)
title: State Management sidebar: label: Overview
import { Badge } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';
State Management
Any reasonably large application will have to deal with state management at some point. State-related code is often one of the biggest boilerplates in your codebase. Well, at least until you start using our state management plugins.
Plugins
Hey API natively supports the following state managers.
Don't see your state manager? Let us know by opening an issue.
Web Src Content Docs Docs Openapi Typescript Validators (`web/src/content/docs/docs/openapi/typescript/validators.mdx`)
title: Validators sidebar: label: Overview
import { Badge } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';
Validators
There are times when you cannot blindly trust the server to return the correct data. You might be working on a critical application where any mistakes would be costly, or you're simply dealing with a legacy or undocumented system.
Validator plugins generate schemas from your input. You can connect them to your client as validators or transformers via the SDK plugin.
Features
- seamless integration with
@hey-api/openapi-tsecosystem - schemas for requests, responses, and reusable definitions
- static type inference from schemas
- tree-shakeable output
Plugins
Hey API natively supports the following validators.
Don't see your validator? Let us know by opening an issue.
Web Src Content Docs Docs Openapi Typescript Web Frameworks (`web/src/content/docs/docs/openapi/typescript/web-frameworks.mdx`)
title: Web Frameworks sidebar: label: Overview
import { Badge } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';
Web Frameworks
There are two approaches to developing APIs: code-first, where you start with the code, or spec-first, where you begin with the specification. If you use the latter, you can ensure your APIs adhere to the specification with our web framework plugins.
Plugins
Hey API natively supports the following frameworks.
Don't see your framework? Let us know by opening an issue.
Web Src Content Docs Docs Openapi Python Clients Aiohttp (`web/src/content/docs/docs/openapi/python/clients/aiohttp.mdx`)
title: AIOHTTP
import FeatureStatus from '@/components/FeatureStatus.astro';
AIOHTTP
About
AIOHTTP is an asynchronous HTTP client/server for asyncio and Python.
Web Src Content Docs Docs Openapi Python Clients Custom (`web/src/content/docs/docs/openapi/python/clients/custom.mdx`)
title: Custom Client sidebar: label: Client
import Examples from '@/components/Examples.astro';
:::caution
Client API is in development. The interface might change before it becomes stable. We encourage you to leave feedback on GitHub.
:::
You may need to write your own client if the available clients do not suit your needs or you're working on a proprietary use case. This can be easily achieved using the Client API. But don't take our word for it – all Hey API clients are written this way!
:::caution
Custom clients documentation will be finalized after further testing. Simplified instructions can be found in the GitHub thread.
:::
Web Src Content Docs Docs Openapi Python Clients Httpx (`web/src/content/docs/docs/openapi/python/clients/httpx.mdx`)
title: HTTPX Client sidebar: label: HTTPX
import { Tabs, TabItem } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';
import StackBlitz from '@/components/StackBlitz.astro';
import UserConfig from '@/components/UserConfig.astro';
HTTPX
About
HTTPX is a fully featured HTTP client for Python 3, which provides sync and async APIs, and support for both HTTP/1.1 and HTTP/2.
The HTTPX client for Hey API generates a type-safe client from your OpenAPI spec, fully compatible with validators, transformers, and all core features.
{/* ### Demo
<StackBlitz
example="hey-api-client-fetch-example"
openFile={[
'openapi-ts.config.ts',
'src/client/schemas.gen.ts',
'src/client/sdk.gen.ts',
'src/client/types.gen.ts',
'src/App.tsx',
]}
/> */}
Features
- seamless integration with
@hey-api/openapi-pythonecosystem - type-safe response data and errors
- response data validation and transformation
- access to the original request and response
- granular request and response customization options
- minimal learning curve thanks to extending the underlying technology
- support bundling inside the generated output
Installation
In your configuration, add @hey-api/client-httpx to your plugins and you'll be ready to generate client artifacts. 🎉
:::note
This step is optional because HTTPX is the default client.
:::
Configuration
The HTTPX client is built as a thin wrapper on top of HTTPX, extending its functionality to work with Hey API. If you're already familiar with HTTPX, configuring your client will feel like working directly with HTTPX.
When we installed the client above, it created a client.gen.ts file. You will most likely want to configure the exported client instance. There are two ways to do that.
`setConfig()`
This is the simpler approach. You can call the setConfig() method at the beginning of your application or anytime you need to update the client configuration. You can pass any HTTPX configuration option to setConfig(), and even your own HTTPX implementation.
import { client } from 'client/client.gen';
client.setConfig({
baseUrl: 'https://example.com',
});The disadvantage of this approach is that your code may call the client instance before it's configured for the first time. Depending on your use case, you might need to use the second approach.
Runtime API
Since client.gen.ts is a generated file, we can't directly modify it. Instead, we can tell our configuration to use a custom file implementing the Runtime API. We do that by specifying the runtimeConfigPath option.
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
{
name: '@hey-api/client-httpx',
runtimeConfigPath: './src/hey-api.ts',
},
],
};In our custom file, we need to export a createClientConfig() method. This function is a simple wrapper allowing us to override configuration values.
import type { CreateClientConfig } from './client/client.gen';
export const createClientConfig: CreateClientConfig = (config) => ({
...config,
baseUrl: 'https://example.com',
});With this approach, client.gen.ts will call createClientConfig() before initializing the client instance. If needed, you can still use setConfig() to update the client configuration later.
`createClient()`
You can also create your own client instance. You can use it to manually send requests or point it to a different domain.
import { createClient } from './client/client';
const myClient = createClient({
baseUrl: 'https://example.com',
});You can also pass this instance to any SDK function through the client option. This will override the default instance from client.gen.ts.
const response = await getFoo({
client: myClient,
});SDKs
Alternatively, you can pass the client configuration options to each SDK function. This is useful if you don't want to create a client instance for one-off use cases.
const response = await getFoo({
baseUrl: 'https://example.com', // <-- override default configuration
});Interceptors
Interceptors (middleware) can be used to modify requests before they're sent or responses before they're returned to your application.
They can be added with use, removed with eject, and updated wth update. The use and update methods will return the ID of the interceptor for use with eject and update. Fetch API does not have the interceptor functionality, so we implement our own.
Example: Request interceptor
async function myInterceptor(request) {
// do something
return request;
}
interceptorId = client.interceptors.request.use(myInterceptor);
</TabItem>
<TabItem label="eject">
```js title="src/index.ts"
import { client } from 'client/client.gen';
// eject by ID
client.interceptors.request.eject(interceptorId);
// eject by reference
client.interceptors.request.eject(myInterceptor);async function myNewInterceptor(request) {
// do something
return request;
}
// update by ID
client.interceptors.request.update(interceptorId, myNewInterceptor);
// update by reference
client.interceptors.request.update(myInterceptor, myNewInterceptor);
</TabItem>
</Tabs>
### Example: Response interceptor
<Tabs>
<TabItem label="use">
```js title="src/index.ts"
import { client } from 'client/client.gen';
async function myInterceptor(response) {
// do something
return response;
}
interceptorId = client.interceptors.response.use(myInterceptor);// eject by ID
client.interceptors.response.eject(interceptorId);
// eject by reference
client.interceptors.response.eject(myInterceptor);
</TabItem>
<TabItem label="update">
```js title="src/index.ts"
import { client } from 'client/client.gen';
async function myNewInterceptor(response) {
// do something
return response;
}
// update by ID
client.interceptors.response.update(interceptorId, myNewInterceptor);
// update by reference
client.interceptors.response.update(myInterceptor, myNewInterceptor);:::tip
To eject, you must provide the ID or reference of the interceptor passed to use(), the ID is the value returned by use() and update().
:::
Auth
The SDKs include auth mechanisms for every endpoint. You will want to configure the auth field to pass the right token for each request. The auth field can be a string or a function returning a string representing the token. The returned value will be attached only to requests that require auth.
import { client } from 'client/client.gen';
client.setConfig({
auth: () => '<my_token>',
baseUrl: 'https://example.com',
});If you're not using SDKs or generating auth, using interceptors is a common approach to configuring auth for each request.
import { client } from 'client/client.gen';
client.interceptors.request.use((request, options) => {
request.headers.set('Authorization', 'Bearer <my_token>');
return request;
});Build URL
If you need to access the compiled URL, you can use the buildUrl() method. It's loosely typed by default to accept almost any value; in practice, you will want to pass a type hint.
type FooData = {
path: {
fooId: number;
};
query?: {
bar?: string;
};
url: '/foo/{fooId}';
};
const url = client.buildUrl<FooData>({
path: {
fooId: 1,
},
query: {
bar: 'baz',
},
url: '/foo/{fooId}',
});
console.log(url); // prints '/foo/1?bar=baz'Custom Instance
You can provide a custom fetch instance. This is useful if you need to extend the default instance with extra functionality, or replace it altogether.
import { client } from 'client/client.gen';
client.setConfig({
fetch: () => {
/* custom `fetch` method */
},
});You can use any of the approaches mentioned in Configuration, depending on how granular you want your custom instance to be.
Web Src Content Docs Docs Openapi Python Clients Requests (`web/src/content/docs/docs/openapi/python/clients/requests.mdx`)
title: Requests
import FeatureStatus from '@/components/FeatureStatus.astro';
Requests
About
Requests is a simple, yet elegant, HTTP library.
Web Src Content Docs Docs Openapi Python Clients Urllib3 (`web/src/content/docs/docs/openapi/python/clients/urllib3.mdx`)
title: urllib3
import FeatureStatus from '@/components/FeatureStatus.astro';
urllib3
About
urllib3 is a powerful, user-friendly HTTP client for Python. urllib3 brings many critical features that are missing from the Python standard libraries.
Web Src Content Docs Docs Openapi Python Plugins Attrs (`web/src/content/docs/docs/openapi/python/plugins/attrs.mdx`)
title: Attrs
import FeatureStatus from '@/components/FeatureStatus.astro';
Attrs
About
Attrs is the Python package that will bring back the joy of writing classes by relieving you from the drudgery of implementing object protocols (aka dunder methods). Trusted by NASA for Mars missions since 2020!
Web Src Content Docs Docs Openapi Python Plugins Custom (`web/src/content/docs/docs/openapi/python/plugins/custom.mdx`)
title: Custom Plugin sidebar: label: Plugin
import { FileTree, Tabs, TabItem } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';
:::caution
Plugin API is in development. The interface might change before it becomes stable. We encourage you to leave feedback on GitHub.
:::
You may need to write your own plugin if the available plugins do not suit your needs or you're working on a proprietary use case. This can be easily achieved using the Plugin API. But don't take our word for it – all Hey API plugins are written this way!
File Structure
We recommend following the design pattern of the native plugins. You can browse the code on GitHub as you follow this tutorial.
First, create a my-plugin folder for your plugin files. Inside, create a barrel file index.ts exporting the plugin.
export { defaultConfig, defineConfig } from './config';
export type { MyPlugin } from './types';Types
index.ts references two files, so we need to create them. types.ts contains the TypeScript interface for your plugin options.
import type { DefinePlugin, Plugin } from '@hey-api/openapi-ts';
export type UserConfig = Plugin.Name<'my-plugin'> &
Plugin.Hooks &
Plugin.UserExports & {
/**
* User-configurable option for your plugin.
*/
user?: number | string | {
age?: number;
name?: string;
};
};
export type Config = Plugin.Name<'my-plugin'> &
Plugin.Hooks &
Plugin.Exports & {
/** Resolved option for your plugin. */
user: {
age: number;
name: string;
};
};
export type MyPlugin = DefinePlugin<UserConfig, Config>;Plugin.Namesets the plugin's unique identifier.Plugin.Hooksallows users to override plugin behavior through event hooks. For example, users can control how schemas are extracted or how symbols are routed to files.Plugin.Exportsadd theincludeInEntryoption, which controls whether your plugin's exports are re-exported from the output entry file.UserConfigis what users write in their config file.Configis the fully resolved shape your handler receives.
Configuration
config.ts defines the runtime configuration for your plugin, including how user input is resolved into Config and the handler function that generates output.
import { definePluginConfig } from '@hey-api/openapi-ts';
import { handler } from './plugin';
import type { MyPlugin } from './types';
export const defaultConfig: MyPlugin['Config'] = {
config: {
user: {
age: 42,
name: 'Stan Smith',
},
},
handler,
name: 'my-plugin',
};
/**
* Type helper for `my-plugin` plugin, returns {@link Plugin.Config} object
*/
export const defineConfig = definePluginConfig(defaultConfig);The config table is a declarative resolution spec. Each field declares its default value and optional coercion rules. To allow users to set either age or name through the user field, we can add coercion rules to transform primitive values into the expected shape.
import { handler } from './plugin';
import type { MyPlugin } from './types';
export const defaultConfig: MyPlugin['Config'] = {
config: {
user: {
$coerce: {
number: (v) => ({ age: v }),
string: (v) => ({ name: v }),
},
age: 42,
name: 'Stan Smith',
},
},
handler,
name: 'my-plugin',
};
/**
- Type helper for
my-pluginplugin, returns {@link Plugin.Config} object
*/
export const defineConfig = definePluginConfig(defaultConfig);
</TabItem>
<TabItem label="input">
```js {8} title="openapi-ts.config.ts"
import { defineConfig } from 'path/to/my-plugin';
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
defineConfig({
user: 'Joe Doe', // or number to set age
}),
],
};Dependencies
Plugins can declare dependencies on other plugins. A dependency will always be included in the output, even if the user hasn't explicitly added it to their plugins config. This is useful when your plugin's output builds on another plugin's types or symbols.
export const defaultConfig: MyPlugin['Config'] = {
config: { ... },
dependencies: ['@hey-api/typescript'],
handler,
name: 'my-plugin',
};Resolving tags
Some dependencies aren't known at authoring time, such as which validator plugin the user has installed. Use resolveTag inside a coerce() call to look up the active plugin for a given tag at resolution time. In most cases, you'll also want to declare a dependency on the field to ensure it's included in the output.
import type { PluginContext } from '@hey-api/openapi-ts';
import { coerce } from '@hey-api/openapi-ts';
export const defaultConfig: MyPlugin['Config'] = {
config: {
$dependencies: ['validator'],
validator: coerce((value, context) => {
if (value === true || value === undefined) {
return (context as PluginContext).resolveTag('validator');
}
return value;
}),
},
dependencies: ['@hey-api/typescript'],
handler,
name: 'my-plugin',
};Handler
The handler function generates the actual output. We recommend implementing it in plugin.ts.
import { $ } from '@hey-api/openapi-ts';
import type { MyPlugin } from './types';
export const handler: MyPlugin['Handler'] = ({ plugin }) => {
plugin.forEach('operation', 'schema', (event) => {
if (event.type === 'operation') {
// do something with the operation
} else if (event.type === 'schema') {
// do something with the schema
}
});
// use the TypeScript DSL to build nodes
const symbolName = plugin.symbol('user');
const node = $.const(symbolName)
.export()
.assign($.literal(plugin.config.user.name));
plugin.node(node);
};Imports
Imports are a type-safe way to reference external symbols your plugin works with. Rather than querying or constructing identifiers manually, you declare them once and access them through plugin.imports anywhere in your handler.
Imports are also visible to users customizing your plugin's behavior. When a user provides hooks like $resolvers, they receive the plugin instance and can access plugin.imports to reference your plugin's imports directly.
export function myPluginImports(plugin: PluginInstance) {
const factory = plugin.symbolFactory;
return {
myLib: factory.register('myLib', { external: 'my-lib' }),
};
}
export type MyPluginImports = ReturnType
</TabItem>
<TabItem label="types">
```ts {1,5} title="types.ts"
import type { MyPluginImports } from './imports';
/** ... */
export type MyPlugin = DefinePlugin<UserConfig, Config, never, MyPluginImports>;export const defaultConfig: MyPlugin['Config'] = {
config: { ... },
handler,
imports: myPluginImports,
name: 'my-plugin',
};
</TabItem>
<TabItem label="handler">
```ts {2} title="plugin.ts"
export const handler: MyPlugin['Handler'] = ({ plugin }) => {
const { myLib } = plugin.imports;
// use myLib as a typed reference when building nodes
};Usage
Once you're satisfied with your plugin, register it in the configuration file.
import { defineConfig } from 'path/to/my-plugin';
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
defineConfig(),
],
};Output
Putting all of this together will generate the following my-plugin.gen.ts file.
export const user = 'Stan Smith';Congratulations! You've successfully created your own plugin! 🎉
Web Src Content Docs Docs Openapi Python Plugins Dataclasses (`web/src/content/docs/docs/openapi/python/plugins/dataclasses.mdx`)
title: Dataclasses
import FeatureStatus from '@/components/FeatureStatus.astro';
Dataclasses
About
Dataclasses is a module that provides a decorator and functions for automatically adding generated special methods such as __init__() and __repr__() to user-defined classes.
Web Src Content Docs Docs Openapi Python Plugins Factory Boy (`web/src/content/docs/docs/openapi/python/plugins/factory-boy.mdx`)
title: Factory Boy
import FeatureStatus from '@/components/FeatureStatus.astro';
Factory Boy
About
Factory Boy is a fixtures replacement based on thoughtbot's factory_bot. As a fixtures replacement tool, it aims to replace static, hard to maintain fixtures with easy-to-use factories for complex objects.
Web Src Content Docs Docs Openapi Python Plugins Faker (`web/src/content/docs/docs/openapi/python/plugins/faker.mdx`)
title: Faker
import FeatureStatus from '@/components/FeatureStatus.astro';
Faker
About
Faker is a Python package that generates fake data for you. Whether you need to bootstrap your database, create good-looking XML documents, fill-in your persistence to stress test it, or anonymize data taken from a production service, Faker is for you.
Web Src Content Docs Docs Openapi Python Plugins Marshmallow (`web/src/content/docs/docs/openapi/python/plugins/marshmallow.mdx`)
title: Marshmallow
import FeatureStatus from '@/components/FeatureStatus.astro';
Marshmallow
About
Marshmallow is an ORM/ODM/framework-agnostic library for converting complex datatypes, such as objects, to and from native Python datatypes.
Web Src Content Docs Docs Openapi Python Plugins Mimesis (`web/src/content/docs/docs/openapi/python/plugins/mimesis.mdx`)
title: Mimesis
import FeatureStatus from '@/components/FeatureStatus.astro';
Mimesis
About
Mimesis is a powerful data generator for Python that can produce a wide range of fake data in multiple languages.
Web Src Content Docs Docs Openapi Python Plugins Pydantic (`web/src/content/docs/docs/openapi/python/plugins/pydantic.mdx`)
title: Pydantic v2 Plugin sidebar: label: Pydantic custom: version: v2
import { Tabs, TabItem } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';
import UserConfig from '@/components/UserConfig.astro';
Pydantic
About
Pydantic is the most widely used data validation library for Python. Fast and extensible, Pydantic plays nicely with your linters/IDE/brain.
The Pydantic plugin for Hey API generates models from your OpenAPI spec, fully compatible with validators, transformers, and all core features.
Features
- Pydantic v2 support
- seamless integration with
@hey-api/openapi-pythonecosystem - Pydantic models for requests, responses, and reusable definitions
- minimal learning curve thanks to extending the underlying technology
Installation
In your configuration, add pydantic to your plugins and you'll be ready to generate Pydantic artifacts. 🎉
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
'pydantic',
],
};SDKs
Pydantic can validate or transform data directly in your SDK. Set validator or transformer to true on the SDK plugin to enable it.
The SDK page covers validators and transformers in more detail.
Output
The Pydantic plugin will generate the following artifacts, depending on the input specification.
Requests
A Pydantic model is generated for every request layer of each endpoint.
const vDeletePetPath = v.object({
petId: v.number(),
});
const vDeletePetQuery = v.object({
additionalMetadata: v.string(),
});
</TabItem>
<TabItem label="config">
```js {8} title="openapi-python.config.ts"
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
{
name: 'pydantic',
requests: true,
},
],
};You can customize the naming and casing pattern for requests schemas using the .name and .case options.
Responses
A single Pydantic model is generated for all endpoint's responses. If the endpoint describes multiple responses, the generated model is a union of all possible response shapes.
You can customize the naming and casing pattern for responses schemas using the .name and .case options.
Definitions
A Pydantic model is generated for every reusable definition from your input.
const vBar = v.object({
bar: v.optional(v.array(v.pipe(v.number(), v.integer()))),
});
</TabItem>
<TabItem label="config">
```js {8} title="openapi-python.config.ts"
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
{
name: 'pydantic',
definitions: true,
},
],
};You can customize the naming and casing pattern for definitions schemas using the .name and .case options.
Metadata
It's often useful to associate a schema with some additional metadata for documentation, code generation, AI structured outputs, form validation, and other purposes. You can set metadata to true to attach descriptions to schemas when available.
For more control over metadata, you can provide your own function. It receives the source schema, the target node object, and the $ builder for populating metadata.
Resolvers
You can further customize this plugin's behavior using resolvers.
{/*
Web Src Content Docs Docs Openapi Typescript Clients Axios (`web/src/content/docs/docs/openapi/typescript/clients/axios.mdx`)
title: Axios v1 Client sidebar: label: Axios custom: version: v1
import { Tabs, TabItem } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';
import StackBlitz from '@/components/StackBlitz.astro';
import UserConfig from '@/components/UserConfig.astro';
Axios
About
Axios is a simple promise based HTTP client for the browser and Node.js. Axios provides a simple to use library in a small package with a very extensible interface.
The Axios client for Hey API generates a type-safe client from your OpenAPI spec, fully compatible with validators, transformers, and all core features.
Demo
<StackBlitz
example="hey-api-client-axios-example"
openFile={[
'openapi-ts.config.ts',
'src/client/schemas.gen.ts',
'src/client/sdk.gen.ts',
'src/client/types.gen.ts',
'src/App.tsx',
]}
/>
Features
- Axios v1 support
- seamless integration with
@hey-api/openapi-tsecosystem - type-safe response data and errors
- response data validation and transformation
- access to the original request and response
- granular request and response customization options
- minimal learning curve thanks to extending the underlying technology
- support bundling inside the generated output
Installation
In your configuration, add @hey-api/client-axios to your plugins and you'll be ready to generate client artifacts. 🎉
Configuration
The Axios client is built as a thin wrapper on top of Axios, extending its functionality to work with Hey API. If you're already familiar with Axios, configuring your client will feel like working directly with Axios.
When we installed the client above, it created a client.gen.ts file. You will most likely want to configure the exported client instance. There are two ways to do that.
`setConfig()`
This is the simpler approach. You can call the setConfig() method at the beginning of your application or anytime you need to update the client configuration. You can pass any Axios configuration option to setConfig() (except for auth), and even your own Axios implementation.
import { client } from 'client/client.gen';
client.setConfig({
baseURL: 'https://example.com',
});The disadvantage of this approach is that your code may call the client instance before it's configured for the first time. Depending on your use case, you might need to use the second approach.
Runtime API
Since client.gen.ts is a generated file, we can't directly modify it. Instead, we can tell our configuration to use a custom file implementing the Runtime API. We do that by specifying the runtimeConfigPath option.
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
{
name: '@hey-api/client-axios',
runtimeConfigPath: './src/hey-api.ts',
},
],
};In our custom file, we need to export a createClientConfig() method. This function is a simple wrapper allowing us to override configuration values.
import type { CreateClientConfig } from './client/client.gen';
export const createClientConfig: CreateClientConfig = (config) => ({
...config,
baseURL: 'https://example.com',
});With this approach, client.gen.ts will call createClientConfig() before initializing the client instance. If needed, you can still use setConfig() to update the client configuration later.
`createClient()`
You can also create your own client instance. You can use it to manually send requests or point it to a different domain.
import { createClient } from './client/client';
const myClient = createClient({
baseURL: 'https://example.com',
});You can also pass this instance to any SDK function through the client option. This will override the default instance from client.gen.ts.
const response = await getFoo({
client: myClient,
});SDKs
Alternatively, you can pass the client configuration options to each SDK function. This is useful if you don't want to create a client instance for one-off use cases.
const response = await getFoo({
baseURL: 'https://example.com', // <-- override default configuration
});Interceptors
Interceptors (middleware) can be used to modify requests before they're sent or responses before they're returned to your application. Axios provides interceptors, please refer to their documentation on interceptors.
We expose the Axios instance through the instance field.
import { client } from 'client/client.gen';
client.instance.interceptors.request.use((config) => {
// do something
return config;
});Auth
The SDKs include auth mechanisms for every endpoint. You will want to configure the auth field to pass the right token for each request. The auth field can be a string or a function returning a string representing the token. The returned value will be attached only to requests that require auth.
import { client } from 'client/client.gen';
client.setConfig({
auth: () => '<my_token>',
baseURL: 'https://example.com',
});If you're not using SDKs or generating auth, using interceptors is a common approach to configuring auth for each request.
import { client } from 'client/client.gen';
client.instance.interceptors.request.use((config) => {
config.headers.set('Authorization', 'Bearer <my_token>');
return config;
});Build URL
If you need to access the compiled URL, you can use the buildUrl() method. It's loosely typed by default to accept almost any value; in practice, you will want to pass a type hint.
type FooData = {
path: {
fooId: number;
};
query?: {
bar?: string;
};
url: '/foo/{fooId}';
};
const url = client.buildUrl<FooData>({
path: {
fooId: 1,
},
query: {
bar: 'baz',
},
url: '/foo/{fooId}',
});
console.log(url); // prints '/foo/1?bar=baz'Custom Instance
You can provide a custom axios instance. This is useful if you need to extend the default instance with extra functionality, or replace it altogether.
import axios from 'axios';
import { client } from 'client/client.gen';
// Customize the default axios instance
axios.defaults.baseURL = 'https://example.com';
client.setConfig({
axios: axios,
});or you can pass an AxiosInstance created with axios.create():
import axios from 'axios';
import { client } from 'client/client.gen';
const customAxiosInstance = axios.create({
baseURL: 'https://example.com',
});
client.setConfig({
axios: customAxiosInstance,
});You can use any of the approaches mentioned in Configuration, depending on how granular you want your custom instance to be.
Web Src Content Docs Docs Openapi Typescript Clients Custom (`web/src/content/docs/docs/openapi/typescript/clients/custom.mdx`)
title: Custom Client sidebar: label: Client
import Examples from '@/components/Examples.astro';
:::caution
Client API is in development. The interface might change before it becomes stable. We encourage you to leave feedback on GitHub.
:::
You may need to write your own client if the available clients do not suit your needs or you're working on a proprietary use case. This can be easily achieved using the Client API. But don't take our word for it – all Hey API clients are written this way!
:::caution
Custom clients documentation will be finalized after further testing. Simplified instructions can be found in the GitHub thread.
:::
Web Src Content Docs Docs Openapi Typescript Clients Effect (`web/src/content/docs/docs/openapi/typescript/clients/effect.mdx`)
title: Effect client sidebar: label: Effect
import FeatureStatus from '@/components/FeatureStatus.astro';
Effect
About
Effect is a powerful TypeScript library designed to help developers easily create complex, synchronous, and asynchronous programs.
Web Src Content Docs Docs Openapi Typescript Clients Fetch (`web/src/content/docs/docs/openapi/typescript/clients/fetch.mdx`)
title: Fetch API Client sidebar: label: Fetch API
import { Tabs, TabItem } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';
import StackBlitz from '@/components/StackBlitz.astro';
import UserConfig from '@/components/UserConfig.astro';
Fetch API
About
The Fetch API provides an interface for fetching resources (including across the network). It is a more powerful and flexible replacement for XMLHttpRequest.
The Fetch API client for Hey API generates a type-safe client from your OpenAPI spec, fully compatible with validators, transformers, and all core features.
Demo
<StackBlitz
example="hey-api-client-fetch-example"
openFile={[
'openapi-ts.config.ts',
'src/client/schemas.gen.ts',
'src/client/sdk.gen.ts',
'src/client/types.gen.ts',
'src/App.tsx',
]}
/>
Features
- seamless integration with
@hey-api/openapi-tsecosystem - type-safe response data and errors
- response data validation and transformation
- access to the original request and response
- granular request and response customization options
- minimal learning curve thanks to extending the underlying technology
- support bundling inside the generated output
Installation
In your configuration, add @hey-api/client-fetch to your plugins and you'll be ready to generate client artifacts. 🎉
:::note
This step is optional because Fetch is the default client.
:::
Configuration
The Fetch client is built as a thin wrapper on top of Fetch API, extending its functionality to work with Hey API. If you're already familiar with Fetch, configuring your client will feel like working directly with Fetch API.
When we installed the client above, it created a client.gen.ts file. You will most likely want to configure the exported client instance. There are two ways to do that.
`setConfig()`
This is the simpler approach. You can call the setConfig() method at the beginning of your application or anytime you need to update the client configuration. You can pass any Fetch API configuration option to setConfig(), and even your own Fetch implementation.
import { client } from 'client/client.gen';
client.setConfig({
baseUrl: 'https://example.com',
});The disadvantage of this approach is that your code may call the client instance before it's configured for the first time. Depending on your use case, you might need to use the second approach.
Runtime API
Since client.gen.ts is a generated file, we can't directly modify it. Instead, we can tell our configuration to use a custom file implementing the Runtime API. We do that by specifying the runtimeConfigPath option.
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
{
name: '@hey-api/client-fetch',
runtimeConfigPath: './src/hey-api.ts',
},
],
};In our custom file, we need to export a createClientConfig() method. This function is a simple wrapper allowing us to override configuration values.
import type { CreateClientConfig } from './client/client.gen';
export const createClientConfig: CreateClientConfig = (config) => ({
...config,
baseUrl: 'https://example.com',
});With this approach, client.gen.ts will call createClientConfig() before initializing the client instance. If needed, you can still use setConfig() to update the client configuration later.
`createClient()`
You can also create your own client instance. You can use it to manually send requests or point it to a different domain.
import { createClient } from './client/client';
const myClient = createClient({
baseUrl: 'https://example.com',
});You can also pass this instance to any SDK function through the client option. This will override the default instance from client.gen.ts.
const response = await getFoo({
client: myClient,
});SDKs
Alternatively, you can pass the client configuration options to each SDK function. This is useful if you don't want to create a client instance for one-off use cases.
const response = await getFoo({
baseUrl: 'https://example.com', // <-- override default configuration
});Interceptors
Interceptors (middleware) can be used to modify requests before they're sent or responses before they're returned to your application.
They can be added with use, removed with eject, and updated wth update. The use and update methods will return the ID of the interceptor for use with eject and update. Fetch API does not have the interceptor functionality, so we implement our own.
Example: Request interceptor
async function myInterceptor(request) {
// do something
return request;
}
interceptorId = client.interceptors.request.use(myInterceptor);
</TabItem>
<TabItem label="eject">
```js title="src/index.ts"
import { client } from 'client/client.gen';
// eject by ID
client.interceptors.request.eject(interceptorId);
// eject by reference
client.interceptors.request.eject(myInterceptor);async function myNewInterceptor(request) {
// do something
return request;
}
// update by ID
client.interceptors.request.update(interceptorId, myNewInterceptor);
// update by reference
client.interceptors.request.update(myInterceptor, myNewInterceptor);
</TabItem>
</Tabs>
### Example: Response interceptor
<Tabs>
<TabItem label="use">
```js title="src/index.ts"
import { client } from 'client/client.gen';
async function myInterceptor(response) {
// do something
return response;
}
interceptorId = client.interceptors.response.use(myInterceptor);// eject by ID
client.interceptors.response.eject(interceptorId);
// eject by reference
client.interceptors.response.eject(myInterceptor);
</TabItem>
<TabItem label="update">
```js title="src/index.ts"
import { client } from 'client/client.gen';
async function myNewInterceptor(response) {
// do something
return response;
}
// update by ID
client.interceptors.response.update(interceptorId, myNewInterceptor);
// update by reference
client.interceptors.response.update(myInterceptor, myNewInterceptor);:::tip
To eject, you must provide the ID or reference of the interceptor passed to use(), the ID is the value returned by use() and update().
:::
Auth
The SDKs include auth mechanisms for every endpoint. You will want to configure the auth field to pass the right token for each request. The auth field can be a string or a function returning a string representing the token. The returned value will be attached only to requests that require auth.
import { client } from 'client/client.gen';
client.setConfig({
auth: () => '<my_token>',
baseUrl: 'https://example.com',
});If you're not using SDKs or generating auth, using interceptors is a common approach to configuring auth for each request.
import { client } from 'client/client.gen';
client.interceptors.request.use((request, options) => {
request.headers.set('Authorization', 'Bearer <my_token>');
return request;
});Build URL
If you need to access the compiled URL, you can use the buildUrl() method. It's loosely typed by default to accept almost any value; in practice, you will want to pass a type hint.
type FooData = {
path: {
fooId: number;
};
query?: {
bar?: string;
};
url: '/foo/{fooId}';
};
const url = client.buildUrl<FooData>({
path: {
fooId: 1,
},
query: {
bar: 'baz',
},
url: '/foo/{fooId}',
});
console.log(url); // prints '/foo/1?bar=baz'Custom Instance
You can provide a custom fetch instance. This is useful if you need to extend the default instance with extra functionality, or replace it altogether.
import { client } from 'client/client.gen';
client.setConfig({
fetch: () => {
/* custom `fetch` method */
},
});You can use any of the approaches mentioned in Configuration, depending on how granular you want your custom instance to be.
Web Src Content Docs Docs Openapi Typescript Clients Got (`web/src/content/docs/docs/openapi/typescript/clients/got.mdx`)
title: Got client sidebar: label: Got
import FeatureStatus from '@/components/FeatureStatus.astro';
Got
About
Got is a human-friendly and powerful HTTP request library for Node.js.
Web Src Content Docs Docs Openapi Typescript Clients Ky (`web/src/content/docs/docs/openapi/typescript/clients/ky.mdx`)
title: Ky v1 Client sidebar: label: Ky custom: version: v1
import { Tabs, TabItem } from '@astrojs/starlight/components';
import AuthorsList from '@/components/AuthorsList.astro';
import Examples from '@/components/Examples.astro';
import UserConfig from '@/components/UserConfig.astro';
import { sebastiaanWouters } from '@/data/people';
Ky
About
Ky is a tiny and elegant JavaScript HTTP client based on the Fetch API.
The Ky client for Hey API generates a type-safe client from your OpenAPI spec, fully compatible with validators, transformers, and all core features.
Collaborators
Features
- seamless integration with
@hey-api/openapi-tsecosystem - type-safe response data and errors
- response data validation and transformation
- access to the original request and response
- granular request and response customization options
- minimal learning curve thanks to extending the underlying technology
- support bundling inside the generated output
Installation
In your configuration, add @hey-api/client-ky to your plugins and you'll be ready to generate client artifacts. 🎉
Configuration
The Ky client is built as a thin wrapper on top of Ky, extending its functionality to work with Hey API. If you're already familiar with Ky, configuring your client will feel like working directly with Ky.
When we installed the client above, it created a client.gen.ts file. You will most likely want to configure the exported client instance. There are two ways to do that.
`setConfig()`
This is the simpler approach. You can call the setConfig() method at the beginning of your application or anytime you need to update the client configuration. You can pass any Ky configuration option to setConfig(), and even your own ky instance.
import { client } from 'client/client.gen';
client.setConfig({
baseUrl: 'https://example.com',
});The disadvantage of this approach is that your code may call the client instance before it's configured for the first time. Depending on your use case, you might need to use the second approach.
Runtime API
Since client.gen.ts is a generated file, we can't directly modify it. Instead, we can tell our configuration to use a custom file implementing the Runtime API. We do that by specifying the runtimeConfigPath option.
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
{
name: '@hey-api/client-ky',
runtimeConfigPath: './src/hey-api.ts',
},
],
};In our custom file, we need to export a createClientConfig() method. This function is a simple wrapper allowing us to override configuration values.
import type { CreateClientConfig } from './client/client.gen';
export const createClientConfig: CreateClientConfig = (config) => ({
...config,
baseUrl: 'https://example.com',
});With this approach, client.gen.ts will call createClientConfig() before initializing the client instance. If needed, you can still use setConfig() to update the client configuration later.
`createClient()`
You can also create your own client instance. You can use it to manually send requests or point it to a different domain.
import { createClient } from './client/client';
const myClient = createClient({
baseUrl: 'https://example.com',
});You can also pass this instance to any SDK function through the client option. This will override the default instance from client.gen.ts.
const response = await getFoo({
client: myClient,
});SDKs
Alternatively, you can pass the client configuration options to each SDK function. This is useful if you don't want to create a client instance for one-off use cases.
const response = await getFoo({
baseUrl: 'https://example.com', // <-- override default configuration
});Interceptors
Interceptors (middleware) can be used to modify requests before they're sent or responses before they're returned to your application.
They can be added with use, removed with eject, and updated wth update. The use and update methods will return the ID of the interceptor for use with eject and update. Ky does not have the interceptor functionality, so we implement our own.
Example: Request interceptor
async function myInterceptor(request) {
// do something
return request;
}
interceptorId = client.interceptors.request.use(myInterceptor);
</TabItem>
<TabItem label="eject">
```js title="src/index.ts"
import { client } from 'client/client.gen';
// eject by ID
client.interceptors.request.eject(interceptorId);
// eject by reference
client.interceptors.request.eject(myInterceptor);async function myNewInterceptor(request) {
// do something
return request;
}
// update by ID
client.interceptors.request.update(interceptorId, myNewInterceptor);
// update by reference
client.interceptors.request.update(myInterceptor, myNewInterceptor);
</TabItem>
</Tabs>
### Example: Response interceptor
<Tabs>
<TabItem label="use">
```js title="src/index.ts"
import { client } from 'client/client.gen';
async function myInterceptor(response) {
// do something
return response;
}
interceptorId = client.interceptors.response.use(myInterceptor);// eject by ID
client.interceptors.response.eject(interceptorId);
// eject by reference
client.interceptors.response.eject(myInterceptor);
</TabItem>
<TabItem label="update">
```js title="src/index.ts"
import { client } from 'client/client.gen';
async function myNewInterceptor(response) {
// do something
return response;
}
// update by ID
client.interceptors.response.update(interceptorId, myNewInterceptor);
// update by reference
client.interceptors.response.update(myInterceptor, myNewInterceptor);:::tip
To eject, you must provide the ID or reference of the interceptor passed to use(), the ID is the value returned by use() and update().
:::
Auth
The SDKs include auth mechanisms for every endpoint. You will want to configure the auth field to pass the right token for each request. The auth field can be a string or a function returning a string representing the token. The returned value will be attached only to requests that require auth.
import { client } from 'client/client.gen';
client.setConfig({
auth: () => '<my_token>',
baseUrl: 'https://example.com',
});If you're not using SDKs or generating auth, using interceptors is a common approach to configuring auth for each request.
import { client } from 'client/client.gen';
client.interceptors.request.use((request, options) => {
request.headers.set('Authorization', 'Bearer <my_token>');
return request;
});Build URL
If you need to access the compiled URL, you can use the buildUrl() method. It's loosely typed by default to accept almost any value; in practice, you will want to pass a type hint.
type FooData = {
path: {
fooId: number;
};
query?: {
bar?: string;
};
url: '/foo/{fooId}';
};
const url = client.buildUrl<FooData>({
path: {
fooId: 1,
},
query: {
bar: 'baz',
},
url: '/foo/{fooId}',
});
console.log(url); // prints '/foo/1?bar=baz'Custom Instance
You can provide a custom ky instance. This is useful if you need to extend the default instance with extra functionality, or replace it altogether.
import { client } from 'client/client.gen';
client.setConfig({
ky: ky.create({
/* custom `ky` instance */
}),
});You can use any of the approaches mentioned in Configuration, depending on how granular you want your custom instance to be.
Web Src Content Docs Docs Openapi Typescript Clients Next Js (`web/src/content/docs/docs/openapi/typescript/clients/next-js.mdx`)
title: Next.js Client sidebar: label: Next.js
import { Tabs, TabItem } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';
import UserConfig from '@/components/UserConfig.astro';
Next.js
About
Next.js is the React framework for the web. Used by some of the world's largest companies, Next.js enables you to create high-quality web applications with the power of React components.
The Next.js client for Hey API generates a type-safe client from your OpenAPI spec, fully compatible with validators, transformers, and all core features.
Features
- seamless integration with
@hey-api/openapi-tsecosystem - type-safe response data and errors
- response data validation and transformation
- access to the original request and response
- granular request and response customization options
- minimal learning curve thanks to extending the underlying technology
- support bundling inside the generated output
Installation
In your configuration, add @hey-api/client-next to your plugins and you'll be ready to generate client artifacts. 🎉
Configuration
The Next.js client is built as a thin wrapper on top of fetch, extending its functionality to work with Hey API. If you're already familiar with Fetch, configuring your client will feel like working directly with Fetch API.
When we installed the client above, it created a client.gen.ts file. You will most likely want to configure the exported client instance. There are two ways to do that.
Runtime API
Since client.gen.ts is a generated file, we can't directly modify it. Instead, we can tell our configuration to use a custom file implementing the Runtime API. We do that by specifying the runtimeConfigPath option.
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
{
name: '@hey-api/client-next',
runtimeConfigPath: './src/hey-api.ts',
},
],
};In our custom file, we need to export a createClientConfig() method. This function is a simple wrapper allowing us to override configuration values.
import type { CreateClientConfig } from './client/client.gen';
export const createClientConfig: CreateClientConfig = (config) => ({
...config,
baseUrl: 'https://example.com',
});With this approach, client.gen.ts will call createClientConfig() before initializing the client instance. This is the recommended approach because it guarantees the client will be initialized in both server and client environment. If needed, you can still use setConfig() to update the client configuration later.
`setConfig()`
This is the simpler approach. You can call the setConfig() method at the beginning of your application or anytime you need to update the client configuration. You can pass any Fetch API configuration option to setConfig(), and even your own Fetch implementation.
import { client } from 'client/client.gen';
client.setConfig({
baseUrl: 'https://example.com',
});The disadvantage of this approach is that your code may call the client instance before it's configured for the first time. Depending on your use case, this might be an acceptable trade-off. However, our Next.js users usually want to use the first approach.
`createClient()`
You can also create your own client instance. You can use it to manually send requests or point it to a different domain.
import { createClient } from './client/client';
const myClient = createClient({
baseUrl: 'https://example.com',
});You can also pass this instance to any SDK function through the client option. This will override the default instance from client.gen.ts.
const response = await getFoo({
client: myClient,
});SDKs
Alternatively, you can pass the client configuration options to each SDK function. This is useful if you don't want to create a client instance for one-off use cases.
const response = await getFoo({
baseUrl: 'https://example.com', // <-- override default configuration
});Interceptors
Interceptors (middleware) can be used to modify requests before they're sent or responses before they're returned to your application.
They can be added with use, removed with eject, and updated wth update. The use and update methods will return the ID of the interceptor for use with eject and update. Fetch API does not have the interceptor functionality, so we implement our own.
Example: Request interceptor
async function myInterceptor(request) {
// do something
return request;
}
interceptorId = client.interceptors.request.use(myInterceptor);
</TabItem>
<TabItem label="eject">
```js title="src/index.ts"
import { client } from 'client/client.gen';
// eject by ID
client.interceptors.request.eject(interceptorId);
// eject by reference
client.interceptors.request.eject(myInterceptor);async function myNewInterceptor(request) {
// do something
return request;
}
// update by ID
client.interceptors.request.update(interceptorId, myNewInterceptor);
// update by reference
client.interceptors.request.update(myInterceptor, myNewInterceptor);
</TabItem>
</Tabs>
### Example: Response interceptor
<Tabs>
<TabItem label="use">
```js title="src/index.ts"
import { client } from 'client/client.gen';
async function myInterceptor(response) {
// do something
return response;
}
interceptorId = client.interceptors.response.use(myInterceptor);// eject by ID
client.interceptors.response.eject(interceptorId);
// eject by reference
client.interceptors.response.eject(myInterceptor);
</TabItem>
<TabItem label="update">
```js title="src/index.ts"
import { client } from 'client/client.gen';
async function myNewInterceptor(response) {
// do something
return response;
}
// update by ID
client.interceptors.response.update(interceptorId, myNewInterceptor);
// update by reference
client.interceptors.response.update(myInterceptor, myNewInterceptor);:::tip
To eject, you must provide the ID or reference of the interceptor passed to use(), the ID is the value returned by use() and update().
:::
Auth
The SDKs include auth mechanisms for every endpoint. You will want to configure the auth field to pass the right token for each request. The auth field can be a string or a function returning a string representing the token. The returned value will be attached only to requests that require auth.
import { client } from 'client/client.gen';
client.setConfig({
auth: () => '<my_token>',
baseUrl: 'https://example.com',
});If you're not using SDKs or generating auth, using interceptors is a common approach to configuring auth for each request.
import { client } from 'client/client.gen';
client.interceptors.request.use((options) => {
options.headers.set('Authorization', 'Bearer <my_token>');
});Build URL
If you need to access the compiled URL, you can use the buildUrl() method. It's loosely typed by default to accept almost any value; in practice, you will want to pass a type hint.
type FooData = {
path: {
fooId: number;
};
query?: {
bar?: string;
};
url: '/foo/{fooId}';
};
const url = client.buildUrl<FooData>({
path: {
fooId: 1,
},
query: {
bar: 'baz',
},
url: '/foo/{fooId}',
});
console.log(url); // prints '/foo/1?bar=baz'Custom Instance
You can provide a custom fetch instance. This is useful if you need to extend the default instance with extra functionality, or replace it altogether.
import { client } from 'client/client.gen';
client.setConfig({
fetch: () => {
/* custom `fetch` method */
},
});You can use any of the approaches mentioned in Configuration, depending on how granular you want your custom instance to be.
Web Src Content Docs Docs Openapi Typescript Clients Nuxt (`web/src/content/docs/docs/openapi/typescript/clients/nuxt.mdx`)
title: Nuxt v3 Client sidebar: label: Nuxt custom: version: v3
import { Tabs, TabItem } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';
import FeatureStatus from '@/components/FeatureStatus.astro';
import InstallCommand from '@/components/package-managers/InstallCommand.astro';
import UserConfig from '@/components/UserConfig.astro';
Nuxt
About
Nuxt is an open source framework that makes web development intuitive and powerful.
The Nuxt client for Hey API generates a type-safe client from your OpenAPI spec, fully compatible with validators, transformers, and all core features.
Features
- Nuxt v3 support
- seamless integration with
@hey-api/openapi-tsecosystem - type-safe response data and errors
- response data validation and transformation
- access to the original request and response
- granular request and response customization options
- minimal learning curve thanks to extending the underlying technology
- support bundling inside the generated output
Installation
Start by adding @hey-api/nuxt to your dependencies.
In your configuration, add @hey-api/client-nuxt to your plugins and you'll be ready to generate client artifacts. 🎉
:::tip
If you add @hey-api/nuxt to your Nuxt modules, this step is not needed.
:::
Configuration
The Nuxt client is built as a thin wrapper on top of Nuxt, extending its functionality to work with Hey API. If you're already familiar with Nuxt, configuring your client will feel like working directly with Nuxt.
When we installed the client above, it created a client.gen.ts file. You will most likely want to configure the exported client instance. There are two ways to do that.
`setConfig()`
This is the simpler approach. You can call the setConfig() method at the beginning of your application or anytime you need to update the client configuration. You can pass any Nuxt configuration option to setConfig(), and even your own $fetch implementation.
import { client } from 'client/client.gen';
client.setConfig({
baseURL: 'https://example.com',
});The disadvantage of this approach is that your code may call the client instance before it's configured for the first time. Depending on your use case, you might need to use the second approach.
Runtime API
Since client.gen.ts is a generated file, we can't directly modify it. Instead, we can tell our configuration to use a custom file implementing the Runtime API. We do that by specifying the runtimeConfigPath option.
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
{
name: '@hey-api/client-nuxt',
runtimeConfigPath: './src/hey-api.ts',
},
],
};In our custom file, we need to export a createClientConfig() method. This function is a simple wrapper allowing us to override configuration values.
import type { CreateClientConfig } from './client/client.gen';
export const createClientConfig: CreateClientConfig = (config) => ({
...config,
baseURL: 'https://example.com',
});With this approach, client.gen.ts will call createClientConfig() before initializing the client instance. If needed, you can still use setConfig() to update the client configuration later.
`createClient()`
You can also create your own client instance. You can use it to manually send requests or point it to a different domain.
import { createClient } from './client/client';
const myClient = createClient({
baseURL: 'https://example.com',
});You can also pass this instance to any SDK function through the client option. This will override the default instance from client.gen.ts.
const response = await getFoo({
client: myClient,
});SDKs
Alternatively, you can pass the client configuration options to each SDK function. This is useful if you don't want to create a client instance for one-off use cases.
const response = await getFoo({
baseURL: 'https://example.com', // <-- override default configuration
});Interceptors
Interceptors (middleware) can be used to modify requests before they're sent or responses before they're returned to your application. Nuxt provides interceptors through ofetch, please refer to their documentation on $fetch.
You can pass any Nuxt/ofetch arguments to the client instance.
:::note
If you omit composable, $fetch is used by default.
:::
import { client } from 'client/client.gen';
const result = await client.get({
composable: '$fetch',
onRequest: (context) => {
// do something
},
url: '/foo',
});Auth
The SDKs include auth mechanisms for every endpoint. You will want to configure the auth field to pass the right token for each request. The auth field can be a string or a function returning a string representing the token. The returned value will be attached only to requests that require auth.
import { client } from 'client/client.gen';
client.setConfig({
auth: () => '<my_token>',
baseURL: 'https://example.com',
});If you're not using SDKs or generating auth, using interceptors is a common approach to configuring auth for each request.
import { client } from 'client/client.gen';
client.setConfig({
onRequest: ({ options }) => {
options.headers.set('Authorization', 'Bearer <my_token>');
},
});Build URL
If you need to access the compiled URL, you can use the buildUrl() method. It's loosely typed by default to accept almost any value; in practice, you will want to pass a type hint.
type FooData = {
path: {
fooId: number;
};
query?: {
bar?: string;
};
url: '/foo/{fooId}';
};
const url = client.buildUrl<FooData>({
path: {
fooId: 1,
},
query: {
bar: 'baz',
},
url: '/foo/{fooId}',
});
console.log(url); // prints '/foo/1?bar=baz'Custom Instance
You can provide a custom $fetch instance. This is useful if you need to extend the default instance with extra functionality, or replace it altogether.
import { client } from 'client/client.gen';
client.setConfig({
$fetch: () => {
/* custom `$fetch` method */
},
});You can use any of the approaches mentioned in Configuration, depending on how granular you want your custom instance to be.
Web Src Content Docs Docs Openapi Typescript Clients Ofetch (`web/src/content/docs/docs/openapi/typescript/clients/ofetch.mdx`)
title: OFetch Client sidebar: label: OFetch
import { Tabs, TabItem } from '@astrojs/starlight/components';
import AuthorsList from '@/components/AuthorsList.astro';
import Examples from '@/components/Examples.astro';
import UserConfig from '@/components/UserConfig.astro';
import { dmitriyBrolnickij } from '@/data/people';
OFetch
About
ofetch is a better Fetch API that adds useful defaults and features such as automatic response parsing, request/response hooks, and it works in Node, browser, and workers.
The ofetch client for Hey API generates a type-safe client from your OpenAPI spec, fully compatible with validators, transformers, and all core features.
Collaborators
Features
- seamless integration with
@hey-api/openapi-tsecosystem - type-safe response data and errors
- response data validation and transformation
- access to the original request and response
- granular request and response customization options
- minimal learning curve thanks to extending the underlying technology
- support bundling inside the generated output
Installation
In your configuration, add @hey-api/client-ofetch to your plugins and you'll be ready to generate client artifacts. 🎉
Configuration
The ofetch client is built as a thin wrapper on top of ofetch, extending its functionality to work with Hey API. If you're already familiar with ofetch, configuring your client will feel like working directly with ofetch.
When we installed the client above, it created a client.gen.ts file. You will most likely want to configure the exported client instance. There are two ways to do that.
`setConfig()`
This is the simpler approach. You can call the setConfig() method at the beginning of your application or anytime you need to update the client configuration. You can pass any ofetch configuration option to setConfig(), and even your own ofetch instance.
import { client } from 'client/client.gen';
client.setConfig({
baseUrl: 'https://example.com',
});The disadvantage of this approach is that your code may call the client instance before it's configured for the first time. Depending on your use case, you might need to use the second approach.
Runtime API
Since client.gen.ts is a generated file, we can't directly modify it. Instead, we can tell our configuration to use a custom file implementing the Runtime API. We do that by specifying the runtimeConfigPath option.
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
{
name: '@hey-api/client-ofetch',
runtimeConfigPath: './src/hey-api.ts',
},
],
};In our custom file, we need to export a createClientConfig() method. This function is a simple wrapper allowing us to override configuration values.
import type { CreateClientConfig } from './client/client.gen';
export const createClientConfig: CreateClientConfig = (config) => ({
...config,
baseUrl: 'https://example.com',
});With this approach, client.gen.ts will call createClientConfig() before initializing the client instance. If needed, you can still use setConfig() to update the client configuration later.
`createClient()`
You can also create your own client instance. You can use it to manually send requests or point it to a different domain.
import { createClient } from './client/client';
const myClient = createClient({
baseUrl: 'https://example.com',
});You can also pass this instance to any SDK function through the client option. This will override the default instance from client.gen.ts.
const response = await getFoo({
client: myClient,
});SDKs
Alternatively, you can pass the client configuration options to each SDK function. This is useful if you don't want to create a client instance for one-off use cases.
const response = await getFoo({
baseUrl: 'https://example.com', // <-- override default configuration
});Interceptors
Interceptors (middleware) can be used to modify requests before they're sent or responses before they're returned to your application.
The ofetch client supports two complementary options:
- built-in Hey API interceptors exposed via
client.interceptors - native
ofetchhooks passed through config (e.g.,onRequest)
Example: Request interceptor
async function myInterceptor(request) {
// do something
return request;
}
interceptorId = client.interceptors.request.use(myInterceptor);
</TabItem>
<TabItem label="eject">
```js title="src/index.ts"
import { client } from 'client/client.gen';
// eject by ID
client.interceptors.request.eject(interceptorId);
// eject by reference
client.interceptors.request.eject(myInterceptor);async function myNewInterceptor(request) {
// do something
return request;
}
// update by ID
client.interceptors.request.update(interceptorId, myNewInterceptor);
// update by reference
client.interceptors.request.update(myInterceptor, myNewInterceptor);
</TabItem>
</Tabs>
### Example: Response interceptor
<Tabs>
<TabItem label="use">
```js title="src/index.ts"
import { client } from 'client/client.gen';
async function myInterceptor(response) {
// do something
return response;
}
interceptorId = client.interceptors.response.use(myInterceptor);// eject by ID
client.interceptors.response.eject(interceptorId);
// eject by reference
client.interceptors.response.eject(myInterceptor);
</TabItem>
<TabItem label="update">
```js title="src/index.ts"
import { client } from 'client/client.gen';
async function myNewInterceptor(response) {
// do something
return response;
}
// update by ID
client.interceptors.response.update(interceptorId, myNewInterceptor);
// update by reference
client.interceptors.response.update(myInterceptor, myNewInterceptor);:::tip
To eject, you must provide the ID or reference of the interceptor passed to use(), the ID is the value returned by use() and update().
:::
Example: `ofetch` hooks
import { client } from 'client/client.gen';
client.setConfig({
onRequest: ({ options }) => {
// mutate ofetch options (headers, query, etc.)
},
onResponse: ({ response }) => {
// inspect/transform the raw Response
},
onRequestError: (ctx) => {
// handle request errors
},
onResponseError: (ctx) => {
// handle response errors
},
});Auth
The SDKs include auth mechanisms for every endpoint. You will want to configure the auth field to pass the right token for each request. The auth field can be a string or a function returning a string representing the token. The returned value will be attached only to requests that require auth.
import { client } from 'client/client.gen';
client.setConfig({
auth: () => '<my_token>',
baseUrl: 'https://example.com',
});If you're not using SDKs or generating auth, using interceptors is a common approach to configuring auth for each request.
import { client } from 'client/client.gen';
client.interceptors.request.use((request, options) => {
request.headers.set('Authorization', 'Bearer <my_token>');
return request;
});You can also use the ofetch hooks.
import { client } from 'client/client.gen';
client.setConfig({
onRequest: ({ options }) => {
options.headers.set('Authorization', 'Bearer <my_token>');
},
});Build URL
If you need to access the compiled URL, you can use the buildUrl() method. It's loosely typed by default to accept almost any value; in practice, you will want to pass a type hint.
type FooData = {
path: {
fooId: number;
};
query?: {
bar?: string;
};
url: '/foo/{fooId}';
};
const url = client.buildUrl<FooData>({
path: {
fooId: 1,
},
query: {
bar: 'baz',
},
url: '/foo/{fooId}',
});
console.log(url); // prints '/foo/1?bar=baz'Custom Instance
You can provide a custom ofetch instance. This is useful if you need to extend the default instance with extra functionality, or replace it altogether.
import { ofetch } from 'ofetch';
import { client } from 'client/client.gen';
const customOFetchInstance = ofetch.create({
onRequest: ({ options }) => {
// customize request
},
onResponse: ({ response }) => {
// customize response
},
});
client.setConfig({
ofetch: customOFetchInstance,
});You can use any of the approaches mentioned in Configuration, depending on how granular you want your custom instance to be.
Web Src Content Docs Docs Openapi Typescript Community Contributing (`web/src/content/docs/docs/openapi/typescript/community/contributing.mdx`)
title: Contributing sidebar: label: Overview
Contributor Manual
Foreword
Hey API is an ecosystem for turning API specifications into production-ready code. It's trusted by thousands of companies – from YC startups to Fortune 500 enterprises – and powers products used by millions worldwide.
We welcome contributors of all backgrounds and experience levels. Whether you're fixing a typo or building a new feature, your input matters. If you need guidance, help with technical writing, or want to bring a feature idea to life, we're here to support you.
:::tip
New to open source? Take a look at the Open Source or First Contributions guides for helpful information on contributing to open source projects.
:::
First Steps
There are many ways to contribute to Hey API. Most of them don't involve writing any code!
Read the documentation. Start with the Get Started guide. If you find anything broken or confusing, you can suggest improvements by clicking "Edit" at the bottom of any page.
Browse open issues. Help others by providing workarounds, asking for clarification, triaging, or suggesting labels on open issues. If you see something you would like to work on, consider opening a pull request.
Participate in discussions. Ask or answer questions, provide feedback, or suggest new ideas. Every idea is welcome, no matter how big or small.
Engage on social media. Help others discover Hey API by engaging with our posts on LinkedIn, Bluesky, or X. Share your experiences with Hey API on Reddit, Slack, or in your own communities and group chats.
Create a new issue. If you can't find a solution, open an issue. The issue template will guide you through the process.
Open a pull request. If you find an issue you would like to fix, open a pull request. If you need help, tag
@mrluboson GitHub, provide enough relevant information, and we will do our best to assist you.
These are some of the best ways not only to contribute to Hey API, but also to learn, connect with others, and share ideas.
Pull Requests
Ready to write some code? We have dedicated guides to help you build, develop, and test your feature before it's released.
We are excited to see what you'll contribute!
Web Src Content Docs Docs Openapi Typescript Community Spotlight (`web/src/content/docs/docs/openapi/typescript/community/spotlight.mdx`)
title: Spotlight
import { coreTeam, hallOfFame } from '@/data/people';
import Contributors from '@/components/Contributors.astro';
import TeamMembers from '@/components/TeamMembers.astro';
Spotlight
Meet the people behind Hey API. To join this list, please refer to the contributing guide.
Core Team
These people actively maintain Hey API.
Do you want to join the core team? Send us a short email describing your interest in Hey API, any relevant experience, and what you're hoping to work on.
Hall of Fame
These are the people with significant contributions to Hey API. A special thank you goes to Ferdi Koomen for allowing us to use the original source code from OpenAPI TypeScript Codegen. None of this would've been possible without you!
Contributors
The complete list of contributors to Hey API.
A sincere thank you for your contributions.
Web Src Content Docs Docs Openapi Typescript Configuration Input (`web/src/content/docs/docs/openapi/typescript/configuration/input.mdx`)
title: Input
import { Tabs, TabItem } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';
import InputTabs from '@/components/code-groups/InputTabs.mdx';
Input
You must provide an input so we can load your OpenAPI specification.
Input
The input can be a string path, URL, API registry, an object containing any of these, or an object representing an OpenAPI specification. Hey API supports all valid OpenAPI versions and file formats.
You can learn more about complex use cases in the Advanced section.
:::tip
If you use an HTTPS URL with a self-signed certificate in development, you will need to set NODE_TLS_REJECT_UNAUTHORIZED=0 in your environment.
:::
Request options
You can pass any valid Fetch API options to the request for fetching your specification. This is useful if your file is behind auth for example.
export default {
input: {
path: 'https://secret.com/protected-spec',
fetch: {
headers: {
Authorization: 'Bearer xxx',
},
},
},
};API Registry
You can store your specifications in an API registry to serve as a single source of truth. This helps prevent drift, improves discoverability, enables version tracking, and more.
Hey API
You can learn more about Hey API Platform on the Integrations page.
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
};The input object lets you provide additional options to construct the correct URL.
export default {
input: {
path: 'hey-api/backend', // sign up at app.heyapi.dev
branch: 'main',
},
};We also provide shorthands for other registries:
ReadMe
Prefix your input with readme: to use the ReadMe API Registry.
Scalar
Prefix your input with scalar: to use the Scalar API Registry.
export default {
input: 'scalar:@scalar/access-service',
};Watch Mode
:::caution
Watch mode currently supports only remote files via URL.
:::
If your schema changes frequently, you may want to automatically regenerate the output during development. To watch your input file for changes, enable input.watch mode in your configuration or pass the --watch flag to the CLI.
Web Src Content Docs Docs Openapi Typescript Configuration Output (`web/src/content/docs/docs/openapi/typescript/configuration/output.mdx`)
title: Output
import { Tabs, TabItem } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';
import OutputTabs from '@/components/code-groups/OutputTabs.mdx';
Output
You must set the output so we know where to generate your files.
Output
Output can be a path to the destination folder or an object containing the destination folder path and optional settings.
You can learn more about complex use cases in the Advanced section.
File
Control how files are named and annotated in the generated output.
File Name
You can customize the naming and casing pattern for files using the fileName option.
By default, we append every file name with a .gen suffix to highlight it's automatically generated. You can customize or disable this suffix using the fileName.suffix option.
File Header
The generated output includes a notice in every file warning that any modifications will be lost when the files are regenerated. You can customize or disable this notice using the header option.
/** ... */
</TabItem>
<TabItem label="config">
```js {4-7} title="openapi-ts.config.ts"
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: {
header: (ctx) => [
'/* eslint-disable */',
...ctx.defaultValue,
],
path: 'src/client',
},
};Module
Control how module specifiers are generated in the output.
Module Extension
Set module.extension to define the file extension used in import specifiers. This is useful when targeting environments that require fully specified imports (e.g., Node ESM or certain bundlers).
Module Path
Use module.resolve for full control over how module specifiers are generated. This lets you override specific modules or redirect them to custom locations (e.g., CDNs or internal aliases).
Source
Source is a copy of the input specification used to generate your output. It can be used to power documentation tools or to persist a stable snapshot alongside your generated files.
Enabling the source option with true creates a source.json file in your output folder.
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: {
path: 'src/client',
source: true,
},
};You can customize the file name and location using fileName and path. For example, this configuration will create an openapi.json file inside src/client/source directory.
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: {
path: 'src/client',
source: {
fileName: 'openapi',
path: './source',
},
},
};To use the source without writing it to disk, you can provide a callback function. This is useful for logging or integrating with external systems.
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: {
path: 'src/client',
source: {
callback: (source) => console.log(source),
path: null,
},
},
};Post Process
Post-processing allows you to run commands on the generated output folder after files are written. This is typically used to run formatters, linters, or other cleanup tools.
Commands are executed in order, and each command receives the output path via the path placeholder.
Presets
You can use built-in presets for common tools:
Custom
You can also provide custom post processors:
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: {
path: 'src/client',
postProcess: [
{
command: 'dprint',
args: ['fmt', '{{path}}'],
},
],
},
};You can skip processing by adding the output path to the tool's ignore file (for example .eslintignore or .prettierignore).
Name Conflicts
As your project grows, the chances of name conflicts increase. We use a simple conflict resolver that appends numeric suffixes to duplicate identifiers. If you prefer a different strategy, you can provide your own nameConflictResolver function.
export type ChatCompletion_N2 = number;
</TabItem>
</Tabs>
## TSConfig Path
We use the [TSConfig file](https://www.typescriptlang.org/tsconfig/) to generate output matching your project's settings. By default, we attempt to find a TSConfig file starting from the location of the `@hey-api/openapi-ts` configuration file and traversing up.
<Tabs>
<TabItem label="default">
```js {5} title="openapi-ts.config.ts"
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: {
path: 'src/client',
tsConfigPath: undefined,
},
};Custom Files
By default, you can't keep custom files in the path folder because it's emptied on every run. If you're sure you need to disable this behavior, set clean to false.
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: {
clean: false,
path: 'src/client',
},
};:::caution
Setting clean to false may result in broken output. Ensure you typecheck your code.
:::
Web Src Content Docs Docs Openapi Typescript Configuration Parser (`web/src/content/docs/docs/openapi/typescript/configuration/parser.mdx`)
title: Parser
import { Tabs, TabItem } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';
Parser
We parse your input before making it available to plugins. Configuring the parser is optional, but it provides an ideal opportunity to modify or validate your input as needed.
Patch
Sometimes you need to modify raw input before it's processed further. A common use case is fixing an invalid specification or adding a missing field. For this reason, custom patches are applied before any parsing takes place.
You can add custom patches with patch.
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
parser: {
patch: {
schemas: {
Foo: (schema) => {
// convert date-time format to timestamp
delete schema.properties.updatedAt.format;
schema.properties.updatedAt.type = 'number';
},
Bar: (schema) => {
// add missing property
schema.properties.meta = {
additionalProperties: true,
type: 'object',
};
schema.required = ['meta'];
},
Baz: (schema) => {
// remove property
delete schema.properties.internalField;
},
},
},
},
};Validate
:::caution
The validator feature is very limited. You can help improve it by submitting more use cases.
:::
If you don't control or trust your input, you might want to validate it. Any detected errors in your input will exit @hey-api/openapi-ts and no plugins will be executed.
To validate your input, set validate_EXPERIMENTAL to true.
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
parser: {
validate_EXPERIMENTAL: true,
},
};Filters
Filters allow you to trim your input before it's processed further, so your output contains only relevant resources.
Operations
Set include to match operations to be included or exclude to match operations to be excluded. Both exact keys and regular expressions are supported. When both rules match the same operation, exclude takes precedence over include.
Tags
Set include to match tags to be included or exclude to match tags to be excluded. When both rules match the same tag, exclude takes precedence over include.
Deprecated
You can filter out deprecated resources by setting deprecated to false.
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
parser: {
filters: {
deprecated: false,
},
},
};Schemas
Set include to match schemas to be included or exclude to match schemas to be excluded. Both exact keys and regular expressions are supported. When both rules match the same schema, exclude takes precedence over include.
Parameters
Set include to match parameters to be included or exclude to match parameters to be excluded. Both exact keys and regular expressions are supported. When both rules match the same parameter, exclude takes precedence over include.
Request Bodies
Set include to match request bodies to be included or exclude to match request bodies to be excluded. Both exact keys and regular expressions are supported. When both rules match the same request body, exclude takes precedence over include.
Responses
Set include to match responses to be included or exclude to match responses to be excluded. Both exact keys and regular expressions are supported. When both rules match the same response, exclude takes precedence over include.
Orphaned resources
If you only want to exclude orphaned resources, set orphans to false. This is the default value when combined with any other filters. If this isn't the desired behavior, you may want to set orphans to true to always preserve unused resources.
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
parser: {
filters: {
orphans: false,
},
},
};Order
For performance reasons, we don't preserve the original order when filtering out resources. If maintaining the original order is important to you, set preserveOrder to true.
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
parser: {
filters: {
preserveOrder: true,
},
},
};Transforms
You can think of transforms as deterministic patches. They provide an easy way to apply the most commonly used input transformations.
Enums
Your input might contain two types of enums:
- enums defined as reusable components (root enums)
- non-reusable enums nested within other schemas (inline enums)
You may want all enums to be reusable. This is because only root enums are typically exported by plugins. Inline enums will never be directly importable since they're nested inside other schemas.
You can customize the naming and casing pattern for enums schemas using the .name and .case options.
Properties required by default
By default, any object schema with a missing required keyword is interpreted as "no properties are required." This is the correct behavior according to the OpenAPI standard. However, some specifications interpret a missing required keyword as "all properties should be required."
This option allows you to change the default behavior so that properties are required by default unless explicitly marked as optional.
Read-write
Your schemas might contain read-only or write-only fields. Using such schemas directly could mean asking the user to provide a read-only field in requests, or expecting a write-only field in responses. We separate schemas for requests and responses if direct usage would result in such scenarios.
You can customize the naming and casing pattern for requests and responses schemas using the .name and .case options.
Schema Name
Sometimes your schema names are auto-generated or follow a naming convention that produces verbose or awkward type names. You can rename schema component keys throughout the specification, automatically updating all $ref pointers. For example, stripping version markers from schema names, removing vendor prefixes, converting naming conventions, or shortening deeply qualified names.
:::note[Name Collisions]
If a transformed schema name conflicts with an existing schema, the rename is skipped for that schema to prevent overwrites. The original name is preserved.
:::
Pagination
Paginated operations are detected by having a pagination keyword in its parameters or request body. By default, we consider the following to be pagination keywords: after, before, cursor, offset, page, and start.
You can provide custom pagination keywords using pagination.keywords.
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
parser: {
pagination: {
keywords: [
...defaultPaginationKeywords,
'extra',
'pagination',
'keywords',
],
},
},
};
</TabItem>
<TabItem label="override">
```js {7-9} title="openapi-ts.config.ts"
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
parser: {
pagination: {
keywords: [
'custom',
'pagination',
'keywords',
],
},
},
};Hooks
Hooks affect runtime behavior but aren't tied to any single plugin. They can be configured globally via hooks or per plugin through the $hooks property.
We always use the first hook that returns a value. If a hook returns no value, we fall back to less specific hooks until one does.
Operations
Each operation has a list of classifiers that can include query, mutation, both, or none. Plugins may use these values to decide whether to generate specific output. For example, you usually don't want to generate TanStack Query options for PATCH operations.
Query operations
By default, GET operations are classified as query operations.
Mutation operations
By default, DELETE, PATCH, POST, and PUT operations are classified as mutation operations.
Example: POST search query
Imagine your API has a POST /search endpoint that accepts a large payload. By default, it's classified as a mutation, but in practice it behaves like a query, and your state management plugin should generate query hooks.
You can achieve this by classifying the operation as query in a matcher.
Symbols
Each symbol can have a placement function deciding its output location.
Example: Alphabetic sort
While we work on a better example, let's imagine a world where it's desirable to place every symbol in a file named after its initial letter. For example, a function named Foo should end up in the file f.ts.
You can achieve this by using the symbol's name.
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
parser: {
hooks: {
symbols: {
getFilePath: (symbol) => {
if (symbol.name) {
return symbol.name[0]?.toLowerCase();
}
},
},
},
},
};Most plugins expose configuration options that allow you to rename many of the generated symbols. If you need even more control, use the getName() hook.
Example: Enum naming
By default, generated enums use the same name for both the type and the runtime value.
export type Flags = (typeof Flags)[keyof typeof Flags];
</TabItem>
<TabItem label="config">
```js title="openapi-ts.config.ts"
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
{
enums: 'javascript',
name: '@hey-api/typescript',
},
],
};While this code works perfectly fine due to TypeScript's declaration merging, let's say we want to use a different name for the type. We can accomplish this with the getName() hook.
export type FlagsType = (typeof Flags)[keyof typeof Flags];
</TabItem>
<TabItem label="config">
```js {10-14} title="openapi-ts.config.ts"
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
{
enums: 'javascript',
name: '@hey-api/typescript',
$hooks: {
symbols: {
getName({ meta, name, schema }) {
if (schema?.type === 'enum' && meta.category === 'type') {
return `${name}Type`;
}
},
},
},
},
],
};Web Src Content Docs Docs Openapi Typescript Configuration Vite (`web/src/content/docs/docs/openapi/typescript/configuration/vite.mdx`)
title: Vite Plugin sidebar: label: Vite
import Examples from '@/components/Examples.astro';
import InstallCommand from '@/components/package-managers/InstallCommand.astro';
Vite
About
Vite is a blazing fast frontend build tool powering the next generation of web applications.
The Vite plugin integrates @hey-api/openapi-ts into the Vite build pipeline, running automatically whenever Vite resolves its configuration – no separate script or manual step required.
Features
- runs automatically as part of your Vite build
- reads your existing configuration (or accepts inline config)
- supports Vite 5, 6, 7, and 8
Installation
You can download @hey-api/vite-plugin from npm using your favorite package manager.
Usage
Add the plugin to your vite.config.ts:
import { heyApiPlugin } from '@hey-api/vite-plugin';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [heyApiPlugin()],
});The plugin will automatically pick up your configuration file. You can also pass options inline using the config option:
import { heyApiPlugin } from '@hey-api/vite-plugin';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [
heyApiPlugin({
config: {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
},
}),
],
});Vite Options
You can pass Vite Plugin API options using the vite option. For example, to run the plugin only during development:
import { heyApiPlugin } from '@hey-api/vite-plugin';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [
heyApiPlugin({
config: {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
},
vite: {
apply: 'serve',
},
}),
],
});Web Src Content Docs Docs Openapi Typescript Plugins Adonis (`web/src/content/docs/docs/openapi/typescript/plugins/adonis.mdx`)
title: AdonisJS sidebar: label: Adonis
import FeatureStatus from '@/components/FeatureStatus.astro';
AdonisJS
About
AdonisJS is a TypeScript-first web framework for building web apps and API servers. It comes with support for testing, modern tooling, an ecosystem of official packages, and more.
Web Src Content Docs Docs Openapi Typescript Plugins Ajv (`web/src/content/docs/docs/openapi/typescript/plugins/ajv.mdx`)
title: Ajv
import FeatureStatus from '@/components/FeatureStatus.astro';
Ajv
About
Ajv is the fastest JSON validator for Node.js and browser.
Web Src Content Docs Docs Openapi Typescript Plugins Arktype (`web/src/content/docs/docs/openapi/typescript/plugins/arktype.mdx`)
title: Arktype
import FeatureStatus from '@/components/FeatureStatus.astro';
Arktype
About
Arktype is a TypeScript's 1:1 validator, optimized from editor to runtime.
Web Src Content Docs Docs Openapi Typescript Plugins Chance (`web/src/content/docs/docs/openapi/typescript/plugins/chance.mdx`)
title: Chance
import FeatureStatus from '@/components/FeatureStatus.astro';
Chance
About
Chance is a minimalist generator of random strings, numbers, etc. to help reduce some monotony particularly while writing automated tests or anywhere else you need anything random.
Web Src Content Docs Docs Openapi Typescript Plugins Custom (`web/src/content/docs/docs/openapi/typescript/plugins/custom.mdx`)
title: Custom Plugin sidebar: label: Plugin
import { FileTree, Tabs, TabItem } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';
:::caution
Plugin API is in development. The interface might change before it becomes stable. We encourage you to leave feedback on GitHub.
:::
You may need to write your own plugin if the available plugins do not suit your needs or you're working on a proprietary use case. This can be easily achieved using the Plugin API. But don't take our word for it – all Hey API plugins are written this way!
File Structure
We recommend following the design pattern of the native plugins. You can browse the code on GitHub as you follow this tutorial.
First, create a my-plugin folder for your plugin files. Inside, create a barrel file index.ts exporting the plugin.
export { defaultConfig, defineConfig } from './config';
export type { MyPlugin } from './types';Types
index.ts references two files, so we need to create them. types.ts contains the TypeScript interface for your plugin options.
import type { DefinePlugin, Plugin } from '@hey-api/openapi-ts';
export type UserConfig = Plugin.Name<'my-plugin'> &
Plugin.Hooks &
Plugin.UserExports & {
/**
* User-configurable option for your plugin.
*/
user?: number | string | {
age?: number;
name?: string;
};
};
export type Config = Plugin.Name<'my-plugin'> &
Plugin.Hooks &
Plugin.Exports & {
/** Resolved option for your plugin. */
user: {
age: number;
name: string;
};
};
export type MyPlugin = DefinePlugin<UserConfig, Config>;Plugin.Namesets the plugin's unique identifier.Plugin.Hooksallows users to override plugin behavior through event hooks. For example, users can control how schemas are extracted or how symbols are routed to files.Plugin.Exportsadd theincludeInEntryoption, which controls whether your plugin's exports are re-exported from the output entry file.UserConfigis what users write in their config file.Configis the fully resolved shape your handler receives.
Configuration
config.ts defines the runtime configuration for your plugin, including how user input is resolved into Config and the handler function that generates output.
import { definePluginConfig } from '@hey-api/openapi-ts';
import { handler } from './plugin';
import type { MyPlugin } from './types';
export const defaultConfig: MyPlugin['Config'] = {
config: {
user: {
age: 42,
name: 'Stan Smith',
},
},
handler,
name: 'my-plugin',
};
/**
* Type helper for `my-plugin` plugin, returns {@link Plugin.Config} object
*/
export const defineConfig = definePluginConfig(defaultConfig);The config table is a declarative resolution spec. Each field declares its default value and optional coercion rules. To allow users to set either age or name through the user field, we can add coercion rules to transform primitive values into the expected shape.
import { handler } from './plugin';
import type { MyPlugin } from './types';
export const defaultConfig: MyPlugin['Config'] = {
config: {
user: {
$coerce: {
number: (v) => ({ age: v }),
string: (v) => ({ name: v }),
},
age: 42,
name: 'Stan Smith',
},
},
handler,
name: 'my-plugin',
};
/**
- Type helper for
my-pluginplugin, returns {@link Plugin.Config} object
*/
export const defineConfig = definePluginConfig(defaultConfig);
</TabItem>
<TabItem label="input">
```js {8} title="openapi-ts.config.ts"
import { defineConfig } from 'path/to/my-plugin';
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
defineConfig({
user: 'Joe Doe', // or number to set age
}),
],
};Dependencies
Plugins can declare dependencies on other plugins. A dependency will always be included in the output, even if the user hasn't explicitly added it to their plugins config. This is useful when your plugin's output builds on another plugin's types or symbols.
export const defaultConfig: MyPlugin['Config'] = {
config: { ... },
dependencies: ['@hey-api/typescript'],
handler,
name: 'my-plugin',
};Resolving tags
Some dependencies aren't known at authoring time, such as which validator plugin the user has installed. Use resolveTag inside a coerce() call to look up the active plugin for a given tag at resolution time. In most cases, you'll also want to declare a dependency on the field to ensure it's included in the output.
import type { PluginContext } from '@hey-api/openapi-ts';
import { coerce } from '@hey-api/openapi-ts';
export const defaultConfig: MyPlugin['Config'] = {
config: {
$dependencies: ['validator'],
validator: coerce((value, context) => {
if (value === true || value === undefined) {
return (context as PluginContext).resolveTag('validator');
}
return value;
}),
},
dependencies: ['@hey-api/typescript'],
handler,
name: 'my-plugin',
};Handler
The handler function generates the actual output. We recommend implementing it in plugin.ts.
import { $ } from '@hey-api/openapi-ts';
import type { MyPlugin } from './types';
export const handler: MyPlugin['Handler'] = ({ plugin }) => {
plugin.forEach('operation', 'schema', (event) => {
if (event.type === 'operation') {
// do something with the operation
} else if (event.type === 'schema') {
// do something with the schema
}
});
// use the TypeScript DSL to build nodes
const symbolName = plugin.symbol('user');
const node = $.const(symbolName)
.export()
.assign($.literal(plugin.config.user.name));
plugin.node(node);
};Imports
Imports are a type-safe way to reference external symbols your plugin works with. Rather than querying or constructing identifiers manually, you declare them once and access them through plugin.imports anywhere in your handler.
Imports are also visible to users customizing your plugin's behavior. When a user provides hooks like $resolvers, they receive the plugin instance and can access plugin.imports to reference your plugin's imports directly.
export function myPluginImports(plugin: PluginInstance) {
const factory = plugin.symbolFactory;
return {
myLib: factory.register('myLib', { external: 'my-lib' }),
};
}
export type MyPluginImports = ReturnType
</TabItem>
<TabItem label="types">
```ts {1,5} title="types.ts"
import type { MyPluginImports } from './imports';
/** ... */
export type MyPlugin = DefinePlugin<UserConfig, Config, never, MyPluginImports>;export const defaultConfig: MyPlugin['Config'] = {
config: { ... },
handler,
imports: myPluginImports,
name: 'my-plugin',
};
</TabItem>
<TabItem label="handler">
```ts {2} title="plugin.ts"
export const handler: MyPlugin['Handler'] = ({ plugin }) => {
const { myLib } = plugin.imports;
// use myLib as a typed reference when building nodes
};Usage
Once you're satisfied with your plugin, register it in the configuration file.
import { defineConfig } from 'path/to/my-plugin';
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
defineConfig(),
],
};Output
Putting all of this together will generate the following my-plugin.gen.ts file.
export const user = 'Stan Smith';Congratulations! You've successfully created your own plugin! 🎉
Web Src Content Docs Docs Openapi Typescript Plugins Elysia (`web/src/content/docs/docs/openapi/typescript/plugins/elysia.mdx`)
title: Elysia
import FeatureStatus from '@/components/FeatureStatus.astro';
Elysia
About
Elysia is an ergonomic framework for humans. TypeScript with end-to-end type safety, type integrity, and exceptional developer experience. Supercharged by Bun.
Web Src Content Docs Docs Openapi Typescript Plugins Express (`web/src/content/docs/docs/openapi/typescript/plugins/express.mdx`)
title: Express
import FeatureStatus from '@/components/FeatureStatus.astro';
Express
About
Express is a minimal and flexible Node.js web application framework that provides a robust set of features for web and mobile applications.
Web Src Content Docs Docs Openapi Typescript Plugins Faker (`web/src/content/docs/docs/openapi/typescript/plugins/faker.mdx`)
title: Faker v10 Plugin sidebar: label: Faker custom: version: v10
import { Tabs, TabItem } from '@astrojs/starlight/components';
import AuthorsList from '@/components/AuthorsList.astro';
import Examples from '@/components/Examples.astro';
import FeatureStatus from '@/components/FeatureStatus.astro';
import UserConfig from '@/components/UserConfig.astro';
import { malcolmKee } from '@/data/people';
Faker
About
Faker is a popular library that generates fake (but reasonable) data that can be used for things such as unit testing, performance testing, building demos, and working without a completed backend.
The Faker plugin for Hey API generates factory functions from your OpenAPI spec that return realistic mock data using @faker-js/faker.
Collaborators
Features
- Faker v9 and v10 support
- seamless integration with
@hey-api/openapi-tsecosystem - factory functions for reusable schema definitions, operation requests, and operation responses
- smart property name inference for realistic data (e.g.
email→faker.internet.email()) - constraint and format awareness (min/max, string formats, array bounds)
- optional property and default value handling
- dependency injection for custom faker instances (locale, seed)
- minimal learning curve thanks to extending the underlying technology
Installation
In your configuration, add @faker-js/faker to your plugins and you'll be ready to generate faker factories. 🎉
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
'@faker-js/faker',
],
};Output
The Faker plugin will generate the following artifacts, depending on the input specification.
Definitions
A factory function is generated for every reusable definition from your input.
import type { Bar, Foo } from '../types.gen';
export const fakeFoo = (options?: Options): Foo => ({
name: ensureFaker(options).string.sample(),
age: ensureFaker(options).number.int({ min: 1, max: 120 }),
});
export const fakeBar = (options?: Options): Bar =>
ensureFaker(options).helpers.arrayElement(['baz', 'qux']);
</TabItem>
<TabItem label="config">
```js {8} title="openapi-ts.config.ts"
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
{
name: '@faker-js/faker',
definitions: true,
},
],
};You can customize the naming and casing pattern for definitions factories using the .name and .case options.
Requests
A single factory function is generated per operation for request data. It combines the request body, path parameters, query parameters, and headers into one object. Only keys with actual data are included.
// body only
export const fakeCreatePetRequest = (options?: Options): Omit<CreatePetData, 'url'> => {
const f = options?.faker ?? faker;
return {
body: {
name: f.string.sample(),
},
};
};
</TabItem>
<TabItem label="config">
```js {8} title="openapi-ts.config.ts"
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
{
name: '@faker-js/faker',
requests: true,
},
],
};You can customize the naming and casing pattern for requests factories using the .name and .case options.
Responses
A factory function is generated for operation responses. When an operation has a single success response, the factory is unsuffixed. When multiple responses exist, each factory is suffixed with the status code.
// multiple responses — suffixed with status code
export const fakeGetPetResponse200 = (options?: Options): GetPetResponses[200] => fakePet(options);
export const fakeGetPetResponse404 = (options?: Options): GetPetErrors[404] => fakeError(options);
</TabItem>
<TabItem label="config">
```js {8} title="openapi-ts.config.ts"
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
{
name: '@faker-js/faker',
responses: true,
},
],
};You can customize the naming and casing pattern for responses factories using the .name and .case options.
Smart Inference
The plugin infers semantically appropriate faker methods from property names, producing more realistic mock data without requiring explicit schema formats or annotations.
// property name "email" → faker.internet.email()
// property name "firstName" → faker.person.firstName()
// property name "city" → faker.location.city()
// property name "id" → faker.string.uuid()
// property name "age" → faker.number.int({ min: 1, max: 120 })Ancestor context is also used for disambiguation. For example, name under a User schema produces faker.person.fullName(), while name under a Company schema produces faker.company.name().
Explicit schema annotations (format, pattern, constraints) always take priority over name-based inference.
Name Rules
You can extend or override the built-in name inference with custom nameRules. Rules are defined per schema type (string or number) and map property names to specific faker methods.
export const fakeDocument = (options?: Options): Document => {
const f = options?.faker ?? faker;
return {
id: f.database.mongodbObjectId(),
_id: f.database.mongodbObjectId(),
};
};
</TabItem>
<TabItem label="config">
```js {8-21} title="openapi-ts.config.ts"
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
{
name: '@faker-js/faker',
nameRules: {
string: {
// compound rule: "message" inside an "error" schema
'error.message': {
fakerPath: ['word', 'words'],
defaultArgs: { count: 4 },
},
// suffix rule: any property ending with "id"
id: {
fakerPath: ['database', 'mongodbObjectId'],
suffixMatch: true,
},
},
},
},
],
};Each rule requires a fakerPath — a tuple of [module, method] corresponding to a faker method (e.g. ['database', 'mongodbObjectId'] for faker.database.mongodbObjectId()). You can optionally provide defaultArgs to pass default arguments to the faker method.
Matching strategies:
- Exact match —
'email'matches a property namedemail - Compound match —
'error.message'matches a property namedmessageinside an ancestor namederror - Suffix match —
'id'withsuffixMatch: truematches any property ending withid(e.g.userId,_id)
User-provided rules take priority over built-in rules. Property names are normalized (lowercased, separators removed) before matching.
Formats and Constraints
The plugin respects OpenAPI schema formats and constraints to generate appropriately bounded data.
String formats:
email→faker.internet.email()date-time→faker.date.recent().toISOString()date→faker.date.recent().toISOString().slice(0, 10)uuid→faker.string.uuid()uri/url→faker.internet.url()ipv4→faker.internet.ipv4()ipv6→faker.internet.ipv6()pattern→faker.helpers.fromRegExp(pattern)
Numeric constraints:
minimum/maximum→faker.number.int({ min, max })exclusiveMinimum/exclusiveMaximum→ adjusted bounds
String constraints:
minLength/maxLength→faker.string.alpha({ length: { min, max } })
Array constraints:
minItems/maxItems→ controls count infaker.helpers.multiple()
Optional Properties
Required properties are always included. Optional properties are controlled by the includeOptional option at runtime.
const user = fakeFoo(); // includes optional properties by default
const user = fakeFoo({ includeOptional: false }); // excludes optional properties
const user = fakeFoo({ includeOptional: 0.5 }); // 50% probability per optional propertyDefault Values
When a schema defines default values, you can control whether to use them instead of generating fake data via the useDefault option.
const data = fakeFoo(); // always generates fake data
const data = fakeFoo({ useDefault: true }); // uses schema defaults when available
const data = fakeFoo({ useDefault: 0.5 }); // 50% probability of using defaultsCircular References
Schemas with circular references are automatically detected, whether self-referencing (a schema that refers to itself) or mutually recursive (two or more schemas that refer to each other). The generated factories use a depth counter to prevent infinite recursion, returning empty arrays or omitting optional properties once the limit is reached.
The maximum depth defaults to 10 and can be configured via the maxCallDepth option.
Locale
You can configure the locale for generated faker factories. When set, the generated code imports the faker instance from the locale-specific build of @faker-js/faker.
See the Faker localization guide for available locales.
Deterministic Results
For snapshot testing or reproducible output, you can seed the faker instance and fix the reference date to ensure deterministic results.
import { faker } from '@faker-js/faker';
faker.seed(42);
faker.setDefaultRefDate('2026-01-01T00:00:00.000Z');
const data = fakeFoo();
// always returns the same outputCustom Faker Instance
You can pass your own faker instance via the faker option for runtime locale switching or other customizations.
import { faker } from '@faker-js/faker/locale/de';
const data = fakeFoo({ faker });Web Src Content Docs Docs Openapi Typescript Plugins Falso (`web/src/content/docs/docs/openapi/typescript/plugins/falso.mdx`)
title: Falso
import FeatureStatus from '@/components/FeatureStatus.astro';
Falso
About
Falso creates massive amounts of fake data in the browser and NodeJS. Tree shakeable & fully typed.
Web Src Content Docs Docs Openapi Typescript Plugins Fastify (`web/src/content/docs/docs/openapi/typescript/plugins/fastify.mdx`)
title: Fastify v5 Plugin sidebar: label: Fastify custom: version: v5
import { Tabs, TabItem } from '@astrojs/starlight/components';
import AuthorsList from '@/components/AuthorsList.astro';
import Examples from '@/components/Examples.astro';
import FeatureStatus from '@/components/FeatureStatus.astro';
import UserConfig from '@/components/UserConfig.astro';
import { jacobCohen } from '@/data/people';
Fastify
About
Fastify is a fast and low overhead web framework for Node.js.
The Fastify plugin for Hey API generates route handlers from your OpenAPI spec, fully compatible with all core features.
Collaborators
Features
- Fastify v5 support
- seamless integration with
@hey-api/openapi-tsecosystem - type-safe route handlers
- minimal learning curve thanks to extending the underlying technology
Installation
In your configuration, add fastify to your plugins and you'll be ready to generate Fastify artifacts. 🎉
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
'fastify',
],
};Output
The Fastify plugin will generate the following artifacts, depending on the input specification.
Route Handlers
Route handlers are generated from all endpoints. The generated interface follows the naming convention of SDK functions.
Web Src Content Docs Docs Openapi Typescript Plugins Hono (`web/src/content/docs/docs/openapi/typescript/plugins/hono.mdx`)
title: Hono
import FeatureStatus from '@/components/FeatureStatus.astro';
Hono
About
Hono is a small, simple, and ultrafast web framework built on Web Standards. It works on any JavaScript runtime: Cloudflare Workers, Fastly Compute, Deno, Bun, Vercel, Netlify, AWS Lambda, Lambda@Edge, and Node.js.
Web Src Content Docs Docs Openapi Typescript Plugins Joi (`web/src/content/docs/docs/openapi/typescript/plugins/joi.mdx`)
title: Joi
import FeatureStatus from '@/components/FeatureStatus.astro';
Joi
About
Joi is the most powerful schema description language and data validator for JavaScript.
Web Src Content Docs Docs Openapi Typescript Plugins Koa (`web/src/content/docs/docs/openapi/typescript/plugins/koa.mdx`)
title: Koa
import FeatureStatus from '@/components/FeatureStatus.astro';
Koa
About
Koa is a new web framework designed by the team behind Express, which aims to be a smaller, more expressive, and more robust foundation for web applications and APIs.
Web Src Content Docs Docs Openapi Typescript Plugins Msw (`web/src/content/docs/docs/openapi/typescript/plugins/msw.mdx`)
title: MSW v2 Plugin sidebar: label: MSW custom: version: v2
import AuthorsList from '@/components/AuthorsList.astro';
import Examples from '@/components/Examples.astro';
import FeatureStatus from '@/components/FeatureStatus.astro';
import UserConfig from '@/components/UserConfig.astro';
import { malcolmKee } from '@/data/people';
MSW
About
MSW is an API mocking library that allows you to write client-agnostic mocks and reuse them across any frameworks, tools, and environments.
The MSW plugin for Hey API generates type-safe mock handler factories from your OpenAPI spec, fully compatible with SDKs, transformers, and all core features.
Collaborators
Features
- MSW v2 support
- seamless integration with
@hey-api/openapi-tsecosystem - type-safe mock handlers
- minimal learning curve thanks to extending the underlying technology
Installation
In your configuration, add msw to your plugins and you'll be ready to generate MSW artifacts. 🎉
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
'msw',
],
};Output
The MSW plugin will generate the following artifacts, depending on the input specification.
Handler Exports
Each operation is exported as a handler creator named <operationId>Mock. These use a wildcard (*) base URL so they match requests regardless of origin. A getAllMocks function is also exported.
import { getPetByIdMock, getAllMocks } from './client/msw.gen';Usage
Static Response
The simplest way to mock an endpoint is to provide a static response object with a result property. The status property is optional — when omitted, it defaults to the operation's dominant success status code (e.g. 200).
import { setupServer } from 'msw/node';
import { getPetByIdMock } from './client/msw.gen';
const mockServer = setupServer(
// result only — status defaults to the dominant success code (200)
getPetByIdMock({ result: { id: 1, name: 'Fido' } }),
// explicit status code
getPetByIdMock({ status: 200, result: { id: 1, name: 'Fido' } }),
// type error if result type is incorrect
// @ts-expect-error
getPetByIdMock({ result: 'wrong type' }),
);Custom Resolver
For more control, pass an MSW HttpResponseResolver function. The resolver receives typed path parameters and request body when available.
import { delay, HttpResponse } from 'msw';
import { setupServer } from 'msw/node';
import { getPetByIdMock, updatePetMock } from './client/msw.gen';
const mockServer = setupServer(
// custom resolver with typed params and body
updatePetMock(async ({ request, params }) => {
const body = await request.json();
return HttpResponse.json({ id: Number(params.petId), ...body }, { status: 200 });
}),
// async resolver with delay
getPetByIdMock(async () => {
await delay(100);
return HttpResponse.json({ id: 1, name: 'Fido' });
}),
);:::note
Path parameters are typed as string because MSW normalizes all path parameters to strings. Use Number() or similar conversions if you need numeric values.
:::
Operations Without Responses
For operations that don't define a response type, the handler creator can be invoked without arguments or with a custom resolver function.
import { deletePetMock } from './client/msw.gen';
const mockServer = setupServer(
deletePetMock(),
deletePetMock(() => new HttpResponse(null, { status: 204 })),
);Response Examples
When your OpenAPI spec includes response examples, the generated handlers will use them as default values. This means you can call the handler without arguments and it will return the example response automatically.
import { getFooMock } from './client/msw.gen';
const mockServer = setupServer(
// uses the example response from the OpenAPI spec as default
getFooMock(),
// you can still override with a custom response
getFooMock({ result: { name: 'Custom' } }),
);By default, source is set to ['@hey-api/examples'], which embeds OpenAPI examples in the generated output. To disable this, set source to an empty array.
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
{
name: 'msw',
source: [],
},
],
};All Handlers (`getAllMocks`)
The getAllMocks function generates handlers for all operations at once. This is useful for quickly setting up a mock server without manually listing each operation.
import { setupServer } from 'msw/node';
import { getAllMocks } from './client/msw.gen';
const server = setupServer(...getAllMocks());`onMissingMock`
Some operations require a response argument (because they have no default example value). The onMissingMock option controls what happens for these operations:
'skip'(default) — skips handlers that require an argument, only including operations that have default values or no response type'error'— includes all handlers, but operations without a provided response return a501error with the message'[heyapi-msw] The mock of this request is not implemented.'
// strict mode: all endpoints are mocked, missing ones return 501
const server = setupServer(...getAllMocks({ onMissingMock: 'error' }));`overrides`
Use overrides to provide static responses for specific operations. The keys are handler names (operation ID suffixed with Mock) and the values are the same as what you'd pass to the individual handler creator.
import { setupServer } from 'msw/node';
import { getAllMocks } from './client/msw.gen';
const server = setupServer(
...getAllMocks({
onMissingMock: 'skip',
overrides: {
getPetByIdMock: {
result: { id: 1, name: 'Fido', photoUrls: [] },
},
},
}),
);When an override is provided for a required handler, it will always be included regardless of the onMissingMock setting.
Custom Base URL
The individually exported handlers use a wildcard (*) base URL that matches requests regardless of origin. If you need handlers bound to a specific base URL, use the createMswHandlerFactory function:
import { setupServer } from 'msw/node';
import { createMswHandlerFactory } from './client/msw.gen';
const createMock = createMswHandlerFactory({
baseUrl: 'http://localhost:8000',
});
const server = setupServer(createMock.getPetByIdMock({ result: { id: 1, name: 'Fido' } }));When called without arguments, the factory infers the base URL from the OpenAPI spec's servers field.
Handler Options
Handler options can be provided. The object will be passed on to MSW helpers.
const mockServer = setupServer(getPetByIdMock({ result: { id: 1, name: 'Fido' } }, { once: true }));Known Limitations
- Query parameters are not typed in the resolver. MSW doesn't provide typed query params natively — use
new URL(request.url).searchParamsinstead. - The response type generic is omitted from
HttpResponseResolverto avoid MSW'sDefaultBodyTypeconstraint issues with union and void response types.
Web Src Content Docs Docs Openapi Typescript Plugins Nest (`web/src/content/docs/docs/openapi/typescript/plugins/nest.mdx`)
title: NestJS v11 Plugin sidebar: label: Nest custom: version: v11
import { Tabs, TabItem } from '@astrojs/starlight/components';
import AuthorsList from '@/components/AuthorsList.astro';
import Examples from '@/components/Examples.astro';
import FeatureStatus from '@/components/FeatureStatus.astro';
import UserConfig from '@/components/UserConfig.astro';
import { yuriMikhin } from '@/data/people';
NestJS
About
Nest is a progressive Node.js framework for building efficient, reliable and scalable server-side applications.
The NestJS plugin for Hey API generates type-safe controller method signatures from your OpenAPI spec, fully compatible with all core features.
Collaborators
Features
- NestJS v11 support
- seamless integration with
@hey-api/openapi-tsecosystem - type-safe controller methods
- minimal learning curve thanks to extending the underlying technology
Installation
In your configuration, add nestjs to your plugins and you'll be ready to generate NestJS artifacts. 🎉
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
'nestjs',
],
};Output
The NestJS plugin will generate the following artifacts, depending on the input specification.
Controller Methods
Operations are grouped by their first tag into separate types.
export type StoreControllerMethods = {
getInventory: () => Promise
};
</TabItem>
<TabItem label="usage">
```ts title="pets.controller.ts"
import { Body, Controller, Get, Param, Post, Query } from '@nestjs/common';
import type { PetsControllerMethods } from '../client/nestjs.gen';
import type { CreatePetData, ListPetsData, ShowPetByIdData } from '../client/types.gen';
@Controller('pets')
export class PetsController implements Pick<
PetsControllerMethods,
'createPet' | 'listPets' | 'showPetById'
> {
@Post()
async createPet(@Body() body: CreatePetData['body']) {}
@Get()
async listPets(@Query() query?: ListPetsData['query']) {}
@Get(':petId')
async showPetById(@Param() path: ShowPetByIdData['path']) {}
}Web Src Content Docs Docs Openapi Typescript Plugins Nock (`web/src/content/docs/docs/openapi/typescript/plugins/nock.mdx`)
title: Nock
import FeatureStatus from '@/components/FeatureStatus.astro';
Nock
About
Nock is an HTTP server mocking and expectations library for Node.js.
Web Src Content Docs Docs Openapi Typescript Plugins Pinia Colada (`web/src/content/docs/docs/openapi/typescript/plugins/pinia-colada.mdx`)
title: Pinia Colada v0 Plugin sidebar: label: Pinia Colada custom: version: v0
import { Tabs, TabItem } from '@astrojs/starlight/components';
import AuthorsList from '@/components/AuthorsList.astro';
import Examples from '@/components/Examples.astro';
import UserConfig from '@/components/UserConfig.astro';
import { joshHemphill, sebastiaanWouters, dmitriyBrolnickij } from '@/data/people';
Pinia Colada
About
Pinia Colada is the perfect companion to Pinia to handle async state management in your Vue applications.
The Pinia Colada plugin for Hey API generates functions and query keys from your OpenAPI spec, fully compatible with SDKs, transformers, and all core features.
Collaborators
<AuthorsList people={[dmitriyBrolnickij, joshHemphill, sebastiaanWouters]} />
Features
- Pinia Colada v0 support
- seamless integration with
@hey-api/openapi-tsecosystem - create query keys following the best practices
- type-safe query options and mutation options
- minimal learning curve thanks to extending the underlying technology
Installation
In your configuration, add @pinia/colada to your plugins and you'll be ready to generate Pinia Colada artifacts. 🎉
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
'@pinia/colada',
],
};:::tip
When using this plugin in a Nuxt app, prefer the ofetch client for universal compatibility.
The nuxt client is tailored for working directly with Nuxt composables ($fetch / useFetch / useAsyncData) and is not intended as a universal HTTP client for libraries like @pinia/colada.
:::
Output
The Pinia Colada plugin will generate the following artifacts, depending on the input specification.
Queries
Queries are generated from query operations. The generated query functions follow the naming convention of SDK functions and by default append Query, e.g., getPetByIdQuery().
You can customize the naming and casing pattern for queryOptions functions using the .name and .case options.
Query Keys
Query keys contain normalized SDK function parameters and additional metadata.
Tags
You can include operation tags in your query keys by setting tags to true. This will make query keys larger but provides better cache invalidation capabilities.
Accessing Query Keys
If you have access to the result of query options function, you can get the query key from the key field.
Alternatively, you can access the same query key by calling query key functions. The generated query key functions follow the naming convention of SDK functions and by default append QueryKey, e.g., getPetByIdQueryKey().
You can customize the naming and casing pattern for queryKeys functions using the .name and .case options.
Mutations
Mutations are generated from mutation operations. The generated mutation functions follow the naming convention of SDK functions and by default append Mutation, e.g., addPetMutation().
addPet.mutate({
body: {
name: 'Kitty',
},
});
</TabItem>
<TabItem label="config">
```js {8} title="openapi-ts.config.ts"
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
{
name: '@pinia/colada',
mutationOptions: true,
},
],
};You can customize the naming and casing pattern for mutationOptions functions using the .name and .case options.
Web Src Content Docs Docs Openapi Typescript Plugins Playwright (`web/src/content/docs/docs/openapi/typescript/plugins/playwright.mdx`)
title: Playwright
import FeatureStatus from '@/components/FeatureStatus.astro';
Playwright
About
Playwright is an end-to-end test framework for modern web apps. It bundles test runner, assertions, isolation, parallelization and rich tooling.
Web Src Content Docs Docs Openapi Typescript Plugins Schemas (`web/src/content/docs/docs/openapi/typescript/plugins/schemas.mdx`)
title: JSON Schema sidebar: label: Schemas
import { Tabs, TabItem } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';
import UserConfig from '@/components/UserConfig.astro';
JSON Schemas
Schemas are located in the schemas.gen.ts file. This file contains runtime schemas generated from your OpenAPI specification definitions located in #/components/schemas. If you're using OpenAPI 3.1, your schemas are fully JSON Schema compliant and can be used with other tools supporting JSON Schema.
Configuration
You can modify the contents of schemas.gen.ts by configuring the @hey-api/schemas plugin. Note that you must specify the default plugins to preserve the default output.
Output
Below is an example output generated in the type: 'form' style. Disabling schemas will not generate the schemas.gen.ts file.
export const PetSchema = {
required: ['name'],
properties: {
id: {
type: 'integer',
format: 'int64',
example: 10,
},
name: {
type: 'string',
example: 'doggie',
},
},
type: 'object',
} as const;Usage
A great use case for schemas is client-side form input validation.
import { $Schema } from './client/schemas.gen';
const maxInputLength = $Schema.properties.text.maxLength;
if (userInput.length > maxInputLength) {
throw new Error(`Text length can't exceed ${maxInputLength} characters!`);
}Web Src Content Docs Docs Openapi Typescript Plugins Sdk (`web/src/content/docs/docs/openapi/typescript/plugins/sdk.mdx`)
title: SDK Plugin sidebar: label: SDK
import { Tabs, TabItem } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';
import UserConfig from '@/components/UserConfig.astro';
SDK
About
The SDK plugin generates a high-level, ergonomic API layer on top of the low-level HTTP client.
It exposes typed functions or methods for each operation, with built-in auth handling, configurable request and response validation, and ready-to-use code examples.
Features
- high-level SDK layer on top of the HTTP client
- typed functions or methods per operation
- built-in authentication handling
- request and response validation
- ready-to-use code examples
Installation
In your configuration, add @hey-api/sdk to your plugins and you'll be ready to generate SDK artifacts. 🎉
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
'@hey-api/sdk',
],
};Output
The SDK plugin supports a wide range of configuration options. This guide focuses on two main SDK formats: tree-shakeable functions and instantiable classes, but you can apply the same concepts to create more advanced configurations.
Flat
This is the default setting. Flat SDKs support tree-shaking, which can lead to a reduced bundle size. You select flat mode by setting operations.strategy to flat.
export const addPet = (options: Options
/** ... */
};
</TabItem>
<TabItem label="config">
```js {9} title="openapi-ts.config.ts"
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
{
name: '@hey-api/sdk',
operations: {
strategy: 'flat',
},
},
],
};Instance
Class SDKs do not support tree-shaking, which results in a larger bundle size, but you may prefer their syntax. You select class mode by setting operations.strategy to single.
export class Sdk extends HeyApiClient {
public addPet(options: Options
/** ... */
}
}
</TabItem>
<TabItem label="config">
```js {9} title="openapi-ts.config.ts"
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
{
name: '@hey-api/sdk',
operations: {
strategy: 'single',
},
},
],
};Name
As shown above, by default our SDK class is called Sdk. The first thing you'll likely want to do is change this to your preferred name, which you can do using operation.containerName.
export class PetStore extends HeyApiClient {
/** ... */
}
</TabItem>
<TabItem label="config">
```js {9} title="openapi-ts.config.ts"
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
{
name: '@hey-api/sdk',
operations: {
containerName: 'PetStore',
strategy: 'single',
},
},
],
};Structure
While we try to infer the SDK structure from operationId fields, you'll likely want to customize it further. You can do this using operations.nesting.
Similar to the operations.strategy option, we provide a few presets. However, you gain the most control by providing your own function.
To demonstrate the power of this feature, let's nest a few endpoints inside a Pet class and rename them. Our original addPet() method will now become pet.add(). Notice that we use the built-in OperationPath.fromOperationId() helper to handle the remaining operations.
export class Pet extends HeyApiClient {
public add(options: Options
/** ... */
}
}
export class PetStore extends HeyApiClient {
get pet(): Pet {
/** ... */
}
}
</TabItem>
<TabItem label="config">
```js {10-18} title="openapi-ts.config.ts"
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
{
name: '@hey-api/sdk',
operations: {
containerName: 'PetStore',
nesting(operation) {
if (operation.path === '/pet/{petId}' || operation.path === '/pet') {
return [
'pet',
operation.operationId?.replace(/Pet/, '') || operation.method.toLocaleLowerCase(),
];
}
return OperationPath.fromOperationId()(operation);
},
strategy: 'single',
},
},
],
};Parameters
By default, all SDK methods accept an object with namespaced properties for each parameter type: query, path, header, and body.
await addPet({
body: {
name: 'Fluffy',
type: 'cat',
},
path: {
petId: 1234,
},
query: {
color: 'red',
},
});
</TabItem>
<TabItem label="config">
```js {8} title="openapi-ts.config.ts"
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
{
name: '@hey-api/sdk',
paramsStructure: 'grouped',
},
],
};If you prefer a more compact syntax, you can set paramsStructure to flat. This will merge all parameter types into a single object, which is especially useful for endpoints with only one parameter type.
await addPet({
color: 'red',
name: 'Fluffy',
petId: 1234,
type: 'cat',
});
</TabItem>
<TabItem label="config">
```js {8} title="openapi-ts.config.ts"
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
{
name: '@hey-api/sdk',
paramsStructure: 'flat',
},
],
};Auth
Most APIs require some form of authentication, which is why the SDK plugin provides built-in auth mechanisms by default. All you need to do is return the data from the auth() function, and the SDK will handle serialization and encoding for you. There are several ways to do this, for example on the client instance.
client.setConfig({
auth() {
return '
},
});
</TabItem>
<TabItem label="config">
```js {7} title="openapi-ts.config.ts"
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
{
auth: true,
name: '@hey-api/sdk',
},
],
};:::note
The SDK plugin currently supports only the bearer and basic auth schemes. Open an issue if you'd like support for additional mechanisms.
:::
Validators
Validating data at runtime comes with a performance cost, which is why it's not enabled by default. To enable validation, set validator to zod or one of the available validator plugins. This will automatically add the selected plugin with its default configuration.
For a more granular approach, manually add a validator plugin and set validator to the plugin name or true to automatically select a compatible plugin. Until you customize the validator plugin, both approaches will produce the same default output.
export const addPet = (options: Options
(options.client ?? client).post<AddPetResponses, AddPetErrors>({
requestValidator: async (data) =>
await v.parseAsync(vAddPetData, data),
responseValidator: async (data) =>
await v.parseAsync(vAddPetResponse, data),
/** ... */
});
</TabItem>
<TabItem label="config">
```js {8,11} title="openapi-ts.config.ts"
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
{
name: '@hey-api/sdk',
validator: true, // or 'valibot'
},
{
name: 'valibot', // customize (optional)
// other options
},
],
};You can choose to validate only requests or responses.
Learn more about available validators on the Validators page.
Transformers
Transformers work similarly to validators, with two differences: transformation applies to responses only, and you use the transformer option instead of validator.
export const addPet = (options: Options
(options.client ?? client).post<AddPetResponses, AddPetErrors>({
responseTransformer: async (data) =>
await v.parseAsync(vAddPetResponse, data),
/** ... */
});
</TabItem>
<TabItem label="config">
```js {8,11} title="openapi-ts.config.ts"
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
{
name: '@hey-api/sdk',
transformer: true, // or 'valibot'
},
{
name: 'valibot', // customize (optional)
// other options
},
],
};Learn more about available transformers on the Validators page.
Metadata
Every SDK method accepts an optional meta object. You can use it to pass arbitrary values that aren't part of the SDK function and read them back in your client interceptors or middleware.
import { addPet } from './sdk.gen.ts';
await addPet({
meta: {
timeout: 5000,
},
});By default meta is untyped, so typos and wrong-typed values compile silently. To make it type-safe, augment the ClientMeta interface exported by your client. After augmentation, meta is fully type-checked at the call site.
await addPet({
meta: {
timeout: 5000, // ✅ correctly typed
timeoutt: 5000, // ❌ unknown key
retry: '5s', // ❌ wrong type
},
});
</TabItem>
</Tabs>
## Code Examples
The SDK plugin can generate ready-to-use code examples for each operation, showing how to call the SDK methods with proper parameters and setup.
Examples are not generated by default, but you can enable and customize them through the `examples` option. With the default settings, an example might look like this.
<Tabs>
<TabItem label="example">
```ts
import { PetStore } from 'your-package';
await new PetStore().addPet();Module and Setup
To make examples more practical, configure moduleName to specify the package from which users import your SDK.
Next, set setupName to indicate how users should instantiate the SDK, typically only once per application.
const client = new PetStore();
await client.addPet();
</TabItem>
<TabItem label="config">
```js {8-9} title="openapi-ts.config.ts"
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
{
examples: {
moduleName: '@petstore/client',
setupName: 'client',
},
name: '@hey-api/sdk',
operations: {
containerName: 'PetStore',
strategy: 'single',
},
},
],
};Initialization
Often, your SDK needs to be instantiated with an API key or other configuration. In examples, importSetup lets you control how the SDK is initialized.
const client = new PetStore({
apiKey: 'YOUR_API_KEY',
});
await client.addPet();
</TabItem>
<TabItem label="config">
```js {8-14} title="openapi-ts.config.ts"
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
{
examples: {
importSetup: ({ $, node }) =>
$.new(
node.name,
$.object()
.pretty()
.prop('apiKey', $.literal('YOUR_API_KEY')),
),
moduleName: '@petstore/client',
setupName: 'client',
},
name: '@hey-api/sdk',
operations: {
containerName: 'PetStore',
strategy: 'single',
},
},
],
};Import Style
If you re-export the generated SDK from your own module, you can adjust importName and importKind to match your actual import style.
const client = new CatStore({
apiKey: 'YOUR_API_KEY',
});
await client.addPet();
</TabItem>
<TabItem label="config">
```js {8-9} title="openapi-ts.config.ts"
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
{
examples: {
importKind: 'default',
importName: 'CatStore',
importSetup: ({ $, node }) =>
$.new(
node.name,
$.object()
.pretty()
.prop('apiKey', $.literal('YOUR_API_KEY')),
),
moduleName: '@petstore/client',
setupName: 'client',
},
name: '@hey-api/sdk',
operations: {
containerName: 'PetStore',
strategy: 'single',
},
},
],
};Payload
You can customize the example request using the payload option. Requests can also be customized selectively. For example, we can provide a default payload only for the addPet() method.
const client = new CatStore({
apiKey: 'YOUR_API_KEY',
});
await client.addPet({
petId: 1234,
});
</TabItem>
<TabItem label="config">
```js {18-23} title="openapi-ts.config.ts"
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
{
examples: {
importKind: 'default',
importName: 'CatStore',
importSetup: ({ $, node }) =>
$.new(
node.name,
$.object()
.pretty()
.prop('apiKey', $.literal('YOUR_API_KEY')),
),
moduleName: '@petstore/client',
payload(operation, ctx) {
const { $ } = ctx;
if (operation.path === '/pet/{petId}' || operation.path === '/pet') {
return $.object().pretty().prop('petId', $.literal(1234));
}
},
setupName: 'client',
},
name: '@hey-api/sdk',
operations: {
containerName: 'PetStore',
strategy: 'single',
},
},
],
};Display
Enabling examples does not produce visible output on its own. Examples are written into the source specification and can be consumed by documentation tools. To persist that specification, enable Source generation.
Web Src Content Docs Docs Openapi Typescript Plugins Superstruct (`web/src/content/docs/docs/openapi/typescript/plugins/superstruct.mdx`)
title: Superstruct
import FeatureStatus from '@/components/FeatureStatus.astro';
Superstruct
About
Superstruct makes it easy to define interfaces and then validate JavaScript data against them.
Web Src Content Docs Docs Openapi Typescript Plugins Supertest (`web/src/content/docs/docs/openapi/typescript/plugins/supertest.mdx`)
title: Supertest
import FeatureStatus from '@/components/FeatureStatus.astro';
Supertest
About
Supertest is a super-agent driven library for testing node.js HTTP servers using a fluent API.
Web Src Content Docs Docs Openapi Typescript Plugins Swr (`web/src/content/docs/docs/openapi/typescript/plugins/swr.mdx`)
title: SWR sidebar: label: SWR
import FeatureStatus from '@/components/FeatureStatus.astro';
SWR
About
SWR is a strategy to first return the data from cache (stale), then send the fetch request (revalidate), and finally come with the up-to-date data.
Web Src Content Docs Docs Openapi Typescript Plugins Tanstack Query (`web/src/content/docs/docs/openapi/typescript/plugins/tanstack-query.mdx`)
title: TanStack Query v5 Plugin sidebar: label: TanStack Query custom: version: v5
import { Tabs, TabItem } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';
import StackBlitz from '@/components/StackBlitz.astro';
import UserConfig from '@/components/UserConfig.astro';
TanStack Query
About
TanStack Query is a powerful asynchronous state management solution for TypeScript/JavaScript, React, Solid, Vue, Svelte, Angular, and Preact.
The TanStack Query plugin for Hey API generates functions and query keys from your OpenAPI spec, fully compatible with SDKs, transformers, and all core features.
Demo
<StackBlitz
example="hey-api-client-fetch-plugin-tanstack-react-query-example"
openFile={[
'openapi-ts.config.ts',
'src/client/@tanstack/react-query.gen.ts',
'src/client/types.gen.ts',
'src/App.tsx',
]}
/>
Features
- TanStack Query v5 support
- seamless integration with
@hey-api/openapi-tsecosystem - create query keys following the best practices
- type-safe query options, infinite query options, and mutation options
- minimal learning curve thanks to extending the underlying technology
Installation
In your configuration, add TanStack Query to your plugins and you'll be ready to generate TanStack Query artifacts. 🎉
Output
The TanStack Query plugin will generate the following artifacts, depending on the input specification.
Queries
Queries are generated from query operations. The generated query functions follow the naming convention of SDK functions and by default append Options, e.g., getPetByIdOptions().
You can customize the naming and casing pattern for queryOptions functions using the .name and .case options.
Meta
You can use the meta field to attach arbitrary information to a query. To generate metadata for queryOptions, provide a function to the .meta option.
Query Keys
Query keys contain normalized SDK function parameters and additional metadata.
Tags
You can include operation tags in your query keys by setting tags to true. This will make query keys larger but provides better cache invalidation capabilities.
Accessing Query Keys
If you have access to the result of query options function, you can get the query key from the queryKey field.
Alternatively, you can access the same query key by calling query key functions. The generated query key functions follow the naming convention of SDK functions and by default append QueryKey, e.g., getPetByIdQueryKey().
You can customize the naming and casing pattern for queryKeys functions using the .name and .case options.
Infinite Queries
Infinite queries are generated from query operations if we detect a pagination parameter. The generated infinite query functions follow the naming convention of SDK functions and by default append InfiniteOptions, e.g., getFooInfiniteOptions().
You can customize the naming and casing pattern for infiniteQueryOptions functions using the .name and .case options.
Meta
You can use the meta field to attach arbitrary information to a query. To generate metadata for infiniteQueryOptions, provide a function to the .meta option.
Infinite Query Keys
Infinite query keys contain normalized SDK function parameters and additional metadata.
Tags
You can include operation tags in your infinite query keys by setting tags to true. This will make query keys larger but provides better cache invalidation capabilities.
Accessing Infinite Query Keys
If you have access to the result of infinite query options function, you can get the query key from the queryKey field.
Alternatively, you can access the same query key by calling query key functions. The generated query key functions follow the naming convention of SDK functions and by default append InfiniteQueryKey, e.g., getPetByIdInfiniteQueryKey().
You can customize the naming and casing pattern for infiniteQueryKeys functions using the .name and .case options.
Mutations
Mutations are generated from mutation operations. The generated mutation functions follow the naming convention of SDK functions and by default append Mutation, e.g., addPetMutation().
addPet.mutate({
body: {
name: 'Kitty',
},
});
</TabItem>
<TabItem label="config">
```js {8} title="openapi-ts.config.ts"
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
{
name: '@tanstack/react-query',
mutationOptions: true,
},
],
};You can customize the naming and casing pattern for mutationOptions functions using the .name and .case options.
Mutation Keys
Mutation keys contain normalized SDK function parameters and additional metadata.
Meta
You can use the meta field to attach arbitrary information to a mutation. To generate metadata for mutationOptions, provide a function to the .meta option.
Reactivity
In Vue applications, you need to wrap the options functions in computed() to make them reactive. Otherwise, TanStack Query won't know it should execute the query when its dependencies change.
Web Src Content Docs Docs Openapi Typescript Plugins Tanstack Start (`web/src/content/docs/docs/openapi/typescript/plugins/tanstack-start.mdx`)
title: TanStack Start
import FeatureStatus from '@/components/FeatureStatus.astro';
TanStack Start
About
TanStack Start is a full-stack framework powered by TanStack Router for React and Solid.
Web Src Content Docs Docs Openapi Typescript Plugins Transformers (`web/src/content/docs/docs/openapi/typescript/plugins/transformers.mdx`)
title: Transformers
import { Tabs, TabItem } from '@astrojs/starlight/components';
import UserConfig from '@/components/UserConfig.astro';
Transformers
:::tip
If you're already using a validator plugin such as Zod or Valibot, you can use it as a transformer too. See your validator plugin's docs for details.
Otherwise, @hey-api/transformers is the right choice.
:::
JSON is the most commonly used data format in REST APIs. However, it does not map well to complex data types. For example, both regular strings and date strings become simple strings in JSON.
One approach to this problem is using a JSON superset. For most people, switching formats is not feasible. That's why we provide the @hey-api/transformers plugin.
Considerations
Before deciding whether transformers are right for you, let's explain how they work. Transformers generate a runtime file, therefore they impact the bundle size. We generate a single transformer per operation response for the most efficient result, just like a human engineer would.
Limitations
Transformers handle only the most common scenarios. Some of the known limitations are:
- union types are not transformed (e.g., if you have multiple possible response shapes)
- only types defined through
$refare transformed - error responses are not transformed
If your data isn't being transformed as expected, we encourage you to leave feedback on GitHub.
Installation
In your configuration, add @hey-api/transformers to your plugins and you'll be ready to generate transformers. 🎉
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
'@hey-api/transformers',
],
};SDKs
To transform response data in your SDKs, set transformer to true on the SDK plugin.
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
'@hey-api/transformers',
{
name: '@hey-api/sdk',
transformer: true,
},
],
};Dates
To convert date strings into Date objects, use the dates configuration option.
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
{
dates: true,
name: '@hey-api/transformers',
},
],
};This will generate types that use Date instead of string and appropriate transformers.
Temporal
To use the Temporal API via temporal-polyfill, set dates to temporal.
import type { GetFooResponse } from './types.gen';
const quxSchemaResponseTransformer = (data: any) => {
if (data.baz) {
data.baz = Temporal.Instant.from(data.baz);
}
return data;
};
const bazSchemaResponseTransformer = (data: any) => {
data = quxSchemaResponseTransformer(data);
data.bar = Temporal.Instant.from(data.bar);
return data;
};
export const getFooResponseTransformer = async (data: any): Promise
data = bazSchemaResponseTransformer(data);
return data;
};
</TabItem>
<TabItem label="config">
```js {7} title="openapi-ts.config.ts"
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
{
dates: 'temporal',
name: '@hey-api/transformers',
},
],
};BigInt
The @hey-api/transformers plugin will natively type all BigInts as bigint instead of number, which can affect arithmetic operations if your application previously used number. To force BigInts to be numbers, use the bigInt configuration option.
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
{
bigInt: true,
name: '@hey-api/transformers',
},
],
};Example
A generated response transformer might look something like this. Please note the example has been edited for brevity.
const quxSchemaResponseTransformer = (data: any) => {
if (data.baz) {
data.baz = new Date(data.baz);
}
return data;
};
const bazSchemaResponseTransformer = (data: any) => {
data = quxSchemaResponseTransformer(data);
data.bar = new Date(data.bar);
return data;
};
export const getFooResponseTransformer = async (data: any): Promise
data = bazSchemaResponseTransformer(data);
return data;
};
</TabItem>
<TabItem label="types.gen.ts">
```ts title="types.gen.ts"
export type Baz = Qux & {
id: 'Baz';
} & {
foo: number;
bar: Date;
baz: 'foo' | 'bar' | 'baz';
qux: number;
};
export type Qux = {
foo: number;
bar: number;
baz?: Date;
id: string;
};
export type GetFooResponse = Baz;Web Src Content Docs Docs Openapi Typescript Plugins Typebox (`web/src/content/docs/docs/openapi/typescript/plugins/typebox.mdx`)
title: TypeBox
import FeatureStatus from '@/components/FeatureStatus.astro';
TypeBox
About
TypeBox is a JSON Schema type builder with static type resolution for TypeScript.
Web Src Content Docs Docs Openapi Typescript Plugins Typescript (`web/src/content/docs/docs/openapi/typescript/plugins/typescript.mdx`)
title: TypeScript sidebar: label: TypeScript
import { Tabs, TabItem } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';
import UserConfig from '@/components/UserConfig.astro';
TypeScript
TypeScript interfaces are located in the types.gen.ts file. This is the only file that does not impact your bundle size and runtime performance. It will get discarded during build time, unless you configured to emit runtime enums.
Installation
In your configuration, add @hey-api/typescript to your plugins and you'll be ready to generate TypeScript artifacts. 🎉
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
'@hey-api/typescript',
],
};:::note
The @hey-api/typescript plugin might be automatically added to your plugins if another plugin depends on it.
:::
Output
The TypeScript plugin will generate the following artifacts, depending on the input specification.
Requests
A single request type is generated for each endpoint. It may contain a request body, parameters, and headers.
export type AddPetData = {
body: {
id?: number;
name: string;
};
path?: never;
query?: never;
url: '/pets';
};You can customize the naming and casing pattern for requests types using the .name and .case options.
Responses
A single type is generated for all endpoint's responses.
export type AddPetResponses = {
200: {
id?: number;
name: string;
};
};
export type AddPetResponse = AddPetResponses[keyof AddPetResponses];You can customize the naming and casing pattern for responses types using the .name and .case options.
Definitions
A type is generated for every reusable definition from your input.
export type Pet = {
id?: number;
name: string;
};You can customize the naming and casing pattern for definitions types using the .name and .case options.
Enums
By default, @hey-api/typescript will emit enums only as types. You may want to generate runtime artifacts. A good use case is iterating through possible field values without manually typing arrays. To emit runtime enums, set enums to a valid option.
We recommend exporting enums as plain JavaScript objects. TypeScript enums are not a type-level extension of JavaScript and pose typing challenges.
Comments
By default, @hey-api/typescript will include comments in the generated code based on descriptions from your OpenAPI specification. If you want to reduce the size of your generated files or prefer cleaner output, you can disable comments.
Resolvers
You can further customize this plugin's behavior using resolvers.
Web Src Content Docs Docs Openapi Typescript Plugins Valibot (`web/src/content/docs/docs/openapi/typescript/plugins/valibot.mdx`)
title: Valibot v1 Plugin sidebar: label: Valibot custom: version: v1
import { Tabs, TabItem } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';
import UserConfig from '@/components/UserConfig.astro';
Valibot
About
Valibot is the open source schema library for TypeScript with bundle size, type safety and developer experience in mind.
The Valibot plugin for Hey API generates schemas from your OpenAPI spec, fully compatible with validators, transformers, and all core features.
Features
- Valibot v1 support
- seamless integration with
@hey-api/openapi-tsecosystem - Valibot schemas for requests, responses, and reusable definitions
- minimal learning curve thanks to extending the underlying technology
Installation
In your configuration, add valibot to your plugins and you'll be ready to generate Valibot artifacts. 🎉
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
'valibot',
],
};SDKs
Valibot can validate or transform data directly in your SDK. Set validator or transformer to true on the SDK plugin to enable it.
The SDK page covers validators and transformers in more detail.
Output
The Valibot plugin will generate the following artifacts, depending on the input specification.
Requests
A Valibot schema is generated for every request layer of each endpoint.
const vDeletePetPath = v.object({
petId: v.number(),
});
const vDeletePetQuery = v.object({
additionalMetadata: v.string(),
});
</TabItem>
<TabItem label="config">
```js {8} title="openapi-ts.config.ts"
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
{
name: 'valibot',
requests: true,
},
],
};You can customize the naming and casing pattern for requests schemas using the .name and .case options.
Responses
A single Valibot schema is generated for all endpoint's responses. If the endpoint describes multiple responses, the generated schema is a union of all possible response shapes.
You can customize the naming and casing pattern for responses schemas using the .name and .case options.
Definitions
A Valibot schema is generated for every reusable definition from your input.
const vBar = v.object({
bar: v.optional(v.array(v.pipe(v.number(), v.integer()))),
});
</TabItem>
<TabItem label="config">
```js {8} title="openapi-ts.config.ts"
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
{
name: 'valibot',
definitions: true,
},
],
};You can customize the naming and casing pattern for definitions schemas using the .name and .case options.
Metadata
It's often useful to associate a schema with some additional metadata for documentation, code generation, AI structured outputs, form validation, and other purposes. You can set metadata to true to attach descriptions to schemas when available.
For more control over metadata, you can provide your own function. It receives the source schema, the target node object, and the $ builder for populating metadata.
Resolvers
You can further customize this plugin's behavior using resolvers.
Web Src Content Docs Docs Openapi Typescript Plugins Yup (`web/src/content/docs/docs/openapi/typescript/plugins/yup.mdx`)
title: Yup
import FeatureStatus from '@/components/FeatureStatus.astro';
Yup
About
Yup is a schema builder for runtime value parsing and validation.
Web Src Content Docs Docs Openapi Typescript Plugins Zustand (`web/src/content/docs/docs/openapi/typescript/plugins/zustand.mdx`)
title: Zustand sidebar: label: Zustand
import FeatureStatus from '@/components/FeatureStatus.astro';
Zustand
About
Zustand is a small, fast, and scalable bearbones state management solution.
Web Src Content Docs Docs Openapi Typescript Clients Angular V19 (`web/src/content/docs/docs/openapi/typescript/clients/angular/v19.mdx`)
title: Angular v19 Client custom: version: v19
import { Tabs, TabItem } from '@astrojs/starlight/components';
import AuthorsList from '@/components/AuthorsList.astro';
import Examples from '@/components/Examples.astro';
import FeatureStatus from '@/components/FeatureStatus.astro';
import UserConfig from '@/components/UserConfig.astro';
import { maxScopp } from '@/data/people';
Angular
About
Angular is a web framework that empowers developers to build fast, reliable applications.
The Angular client for Hey API generates a type-safe client from your OpenAPI spec, fully compatible with validators, transformers, and all core features.
Collaborators
Features
- Angular v19 support
- seamless integration with
@hey-api/openapi-tsecosystem - type-safe response data and errors
- support for
@Injectable()decorators - response data validation and transformation
- access to the original request and response
- granular request and response customization options
- minimal learning curve thanks to extending the underlying technology
- support bundling inside the generated output
Installation
In your configuration, add @hey-api/client-angular to your plugins and you'll be ready to generate client artifacts. 🎉
Providers
You can use the Angular client in your application by adding provideHeyApiClient to your providers.
import { provideHeyApiClient, client } from './client/client.gen';
export const appConfig: ApplicationConfig = {
providers: [
provideHttpClient(withFetch()),
provideHeyApiClient(client),
],
};Configuration
The Angular client is built as a thin wrapper on top of Angular, extending its functionality to work with Hey API. If you're already familiar with Angular, configuring your client will feel like working directly with Angular.
When we installed the client above, it created a client.gen.ts file. You will most likely want to configure the exported client instance. There are two ways to do that.
`setConfig()`
This is the simpler approach. You can call the setConfig() method at the beginning of your application or anytime you need to update the client configuration. You can pass any HttpRequest configuration option to setConfig(), and even your own httpClient implementation.
import { client } from 'client/client.gen';
client.setConfig({
baseUrl: 'https://example.com',
});The disadvantage of this approach is that your code may call the client instance before it's configured for the first time. Depending on your use case, you might need to use the second approach.
Runtime API
Since client.gen.ts is a generated file, we can't directly modify it. Instead, we can tell our configuration to use a custom file implementing the Runtime API. We do that by specifying the runtimeConfigPath option.
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
{
name: '@hey-api/client-angular',
runtimeConfigPath: './src/hey-api.ts',
},
],
};In our custom file, we need to export a createClientConfig() method. This function is a simple wrapper allowing us to override configuration values.
import type { CreateClientConfig } from './client/client.gen';
export const createClientConfig: CreateClientConfig = (config) => ({
...config,
baseUrl: 'https://example.com',
});With this approach, client.gen.ts will call createClientConfig() before initializing the client instance. If needed, you can still use setConfig() to update the client configuration later.
`createClient()`
You can also create your own client instance. You can use it to manually send requests or point it to a different domain.
import { createClient } from './client/client';
const myClient = createClient({
baseUrl: 'https://example.com',
});You can also pass this instance to any SDK function through the client option. This will override the default instance from client.gen.ts.
const response = await getFoo({
client: myClient,
});SDKs
Alternatively, you can pass the client configuration options to each SDK function. This is useful if you don't want to create a client instance for one-off use cases.
const response = await getFoo({
baseUrl: 'https://example.com', // <-- override default configuration
});`@Injectable`
If you prefer to use the @Injectable() decorators, set the asClass option in your SDK plugin to true.
Interceptors
:::caution
This section is under construction. We appreciate your patience.
:::
Auth
:::caution
This section is under construction. We appreciate your patience.
:::
Build URL
If you need to access the compiled URL, you can use the buildUrl() method. It's loosely typed by default to accept almost any value; in practice, you will want to pass a type hint.
type FooData = {
path: {
fooId: number;
};
query?: {
bar?: string;
};
url: '/foo/{fooId}';
};
const url = client.buildUrl<FooData>({
path: {
fooId: 1,
},
query: {
bar: 'baz',
},
url: '/foo/{fooId}',
});
console.log(url); // prints '/foo/1?bar=baz'Custom Instance
You can provide a custom httpClient instance. This is useful if you need to extend the default instance with extra functionality, or replace it altogether.
import { client } from 'client/client.gen';
client.setConfig({
httpClient: inject(CustomHttpClient),
});You can use any of the approaches mentioned in Configuration, depending on how granular you want your custom instance to be.
Plugins
You might be also interested in the Angular plugin.
Web Src Content Docs Docs Openapi Typescript Clients Angular V20 (`web/src/content/docs/docs/openapi/typescript/clients/angular/v20.mdx`)
title: Angular v20 Client sidebar: label: Angular custom: version: v20
import { Tabs, TabItem } from '@astrojs/starlight/components';
import AuthorsList from '@/components/AuthorsList.astro';
import Examples from '@/components/Examples.astro';
import FeatureStatus from '@/components/FeatureStatus.astro';
import UserConfig from '@/components/UserConfig.astro';
import { maxScopp } from '@/data/people';
Angular
About
Angular is a web framework that empowers developers to build fast, reliable applications.
The Angular client for Hey API generates a type-safe client from your OpenAPI spec, fully compatible with validators, transformers, and all core features.
Collaborators
Features
- Angular v20 support
- seamless integration with
@hey-api/openapi-tsecosystem - type-safe response data and errors
- support for
@Injectable()decorators - response data validation and transformation
- access to the original request and response
- granular request and response customization options
- minimal learning curve thanks to extending the underlying technology
- support bundling inside the generated output
Installation
In your configuration, add @hey-api/client-angular to your plugins and you'll be ready to generate client artifacts. 🎉
Providers
You can use the Angular client in your application by adding provideHeyApiClient to your providers.
import { provideHeyApiClient, client } from './client/client.gen';
export const appConfig: ApplicationConfig = {
providers: [
provideHttpClient(withFetch()),
provideHeyApiClient(client),
],
};Configuration
The Angular client is built as a thin wrapper on top of Angular, extending its functionality to work with Hey API. If you're already familiar with Angular, configuring your client will feel like working directly with Angular.
When we installed the client above, it created a client.gen.ts file. You will most likely want to configure the exported client instance. There are two ways to do that.
`setConfig()`
This is the simpler approach. You can call the setConfig() method at the beginning of your application or anytime you need to update the client configuration. You can pass any HttpRequest configuration option to setConfig(), and even your own httpClient implementation.
import { client } from 'client/client.gen';
client.setConfig({
baseUrl: 'https://example.com',
});The disadvantage of this approach is that your code may call the client instance before it's configured for the first time. Depending on your use case, you might need to use the second approach.
Runtime API
Since client.gen.ts is a generated file, we can't directly modify it. Instead, we can tell our configuration to use a custom file implementing the Runtime API. We do that by specifying the runtimeConfigPath option.
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
{
name: '@hey-api/client-angular',
runtimeConfigPath: './src/hey-api.ts',
},
],
};In our custom file, we need to export a createClientConfig() method. This function is a simple wrapper allowing us to override configuration values.
import type { CreateClientConfig } from './client/client.gen';
export const createClientConfig: CreateClientConfig = (config) => ({
...config,
baseUrl: 'https://example.com',
});With this approach, client.gen.ts will call createClientConfig() before initializing the client instance. If needed, you can still use setConfig() to update the client configuration later.
`createClient()`
You can also create your own client instance. You can use it to manually send requests or point it to a different domain.
import { createClient } from './client/client';
const myClient = createClient({
baseUrl: 'https://example.com',
});You can also pass this instance to any SDK function through the client option. This will override the default instance from client.gen.ts.
const response = await getFoo({
client: myClient,
});SDKs
Alternatively, you can pass the client configuration options to each SDK function. This is useful if you don't want to create a client instance for one-off use cases.
const response = await getFoo({
baseUrl: 'https://example.com', // <-- override default configuration
});`@Injectable`
If you prefer to use the @Injectable() decorators, set the asClass option in your SDK plugin to true.
Interceptors
:::caution
This section is under construction. We appreciate your patience.
:::
Auth
:::caution
This section is under construction. We appreciate your patience.
:::
Build URL
If you need to access the compiled URL, you can use the buildUrl() method. It's loosely typed by default to accept almost any value; in practice, you will want to pass a type hint.
type FooData = {
path: {
fooId: number;
};
query?: {
bar?: string;
};
url: '/foo/{fooId}';
};
const url = client.buildUrl<FooData>({
path: {
fooId: 1,
},
query: {
bar: 'baz',
},
url: '/foo/{fooId}',
});
console.log(url); // prints '/foo/1?bar=baz'Custom Instance
You can provide a custom httpClient instance. This is useful if you need to extend the default instance with extra functionality, or replace it altogether.
import { client } from 'client/client.gen';
client.setConfig({
httpClient: inject(CustomHttpClient),
});You can use any of the approaches mentioned in Configuration, depending on how granular you want your custom instance to be.
Plugins
You might be also interested in the Angular plugin.
Web Src Content Docs Docs Openapi Typescript Community Contributing Building (`web/src/content/docs/docs/openapi/typescript/community/contributing/building.mdx`)
title: Building
Building
:::caution
This page is under construction. We appreciate your patience.
:::
Prerequisites
You should have a working knowledge of git, node, and pnpm.
Guidelines
Your pull request must:
- address a single issue or add a single item of functionality
- contain a clean history of small, incremental, logically separate commits, with no merge commits
- use clear commit messages
- be possible to merge automatically
Start `@hey-api/openapi-ts`
Run pnpm --filter @hey-api/openapi-ts dev.
Web Src Content Docs Docs Openapi Typescript Community Contributing Developing (`web/src/content/docs/docs/openapi/typescript/community/contributing/developing.mdx`)
title: Developing
import { Tabs, TabItem } from '@astrojs/starlight/components';
Developing
:::caution
This page is under construction. We appreciate your patience.
:::
Working with Examples
The examples folder contains various integration examples that demonstrate how to use @hey-api/openapi-ts with different frameworks and libraries. These examples are kept in sync with the codebase through automated checks.
Generating Example Code
When you make changes to the core packages that affect code generation, you need to regenerate the client code in all examples:
pnpm examples:updateThis command will:
- Find all examples with an
openapi-tsscript - Run the OpenAPI code generator for each example
- Update the generated client code in each example
Checking Example Code
Before committing changes, ensure that all generated example code is up-to-date:
pnpm examples:checkThis command will:
- Regenerate all example code
- Check if any files were modified
- Exit with an error if generated code is out of sync
This check is also run automatically in CI to ensure examples stay in sync with the main codebase.
Example Workflow
- Make changes to core packages
- Build the packages:
pnpm build --filter="@hey-api/**" - Regenerate examples:
pnpm examples:update - Commit all changes including the updated generated code
- The CI will verify that examples are in sync
:::tip
Think of generated example code as snapshot tests - they should always reflect the current state of the code generator.
:::
Writing Changelogs
We use Changesets to manage releases and generate changelogs. When contributing changes, create a changeset to document your updates.
Creating a Changeset
Run the following command to create a new changeset:
pnpm changesetThis will prompt you to:
- Select the packages that were changed
- Choose the semver bump type (major, minor, or patch)
- Write a summary of your changes
Changeset Format
Changesets use the following format:
---
"@hey-api/openapi-ts": patch
---
**scope**: description of changesScopes:
cli,parser,output,config,input,internal,build,error→ Core sectionplugin(name)→ Plugins section (e.g.,**plugin(zod)**:,**plugin(@hey-api/client-axios)**:)- Any other scope → Other section
Breaking Changes:
- Use
**BREAKING**:prefix in the description to mark breaking changes - For packages on v0.x (major version 0), minor bumps may include breaking changes. Use signal words like "removed", "renamed", or "changed signature" to indicate breaking changes.
Examples
parser: fix explicit discriminator mapping
</TabItem>
<TabItem label="New feature">
```md title="example.changeset.md"
---
"@hey-api/openapi-ts": minor
---
**plugin(zod)**: handle guid string formatBREAKING: removed deprecated getClient() function
</TabItem>
<TabItem label="Plugin change">
```md title="example.changeset.md"
---
"@hey-api/openapi-ts": patch
---
**plugin(@hey-api/client-fetch)**: improve error handlingWeb Src Content Docs Docs Openapi Typescript Community Contributing Testing (`web/src/content/docs/docs/openapi/typescript/community/contributing/testing.mdx`)
title: Testing
Testing
:::caution
This page is under construction. We appreciate your patience.
:::
Web Src Content Docs Docs Openapi Typescript Plugins Angular V19 (`web/src/content/docs/docs/openapi/typescript/plugins/angular/v19.mdx`)
title: Angular v19 Plugin custom: version: v19
import { Tabs, TabItem } from '@astrojs/starlight/components';
import AuthorsList from '@/components/AuthorsList.astro';
import Examples from '@/components/Examples.astro';
import FeatureStatus from '@/components/FeatureStatus.astro';
import UserConfig from '@/components/UserConfig.astro';
import { maxScopp } from '@/data/people';
Angular
About
Angular is a web framework that empowers developers to build fast, reliable applications.
The Angular plugin for Hey API generates HTTP requests and resources from your OpenAPI spec, fully compatible with validators, transformers, and all core features.
Collaborators
Features
- Angular v19 support
- seamless integration with
@hey-api/openapi-tsecosystem - generate HTTP requests
- generate HTTP resources
- minimal learning curve thanks to extending the underlying technology
Installation
In your configuration, add @angular/common to your plugins and you'll be ready to generate Angular artifacts. 🎉
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
'@angular/common',
],
};Output
The Angular plugin will generate the following artifacts, depending on the input specification.
Requests
A single function is generated for each endpoint. It returns an HttpRequest result.
Resources
A single function is generated for each endpoint. It returns a result from httpResource call.
Web Src Content Docs Docs Openapi Typescript Plugins Angular V20 (`web/src/content/docs/docs/openapi/typescript/plugins/angular/v20.mdx`)
title: Angular v20 Plugin sidebar: label: Angular custom: version: v20
import { Tabs, TabItem } from '@astrojs/starlight/components';
import AuthorsList from '@/components/AuthorsList.astro';
import Examples from '@/components/Examples.astro';
import FeatureStatus from '@/components/FeatureStatus.astro';
import UserConfig from '@/components/UserConfig.astro';
import { maxScopp } from '@/data/people';
Angular
About
Angular is a web framework that empowers developers to build fast, reliable applications.
The Angular plugin for Hey API generates HTTP requests and resources from your OpenAPI spec, fully compatible with validators, transformers, and all core features.
Collaborators
Features
- Angular v20 support
- seamless integration with
@hey-api/openapi-tsecosystem - generate HTTP requests
- generate HTTP resources
- minimal learning curve thanks to extending the underlying technology
Installation
In your configuration, add @angular/common to your plugins and you'll be ready to generate Angular artifacts. 🎉
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
'@angular/common',
],
};Output
The Angular plugin will generate the following artifacts, depending on the input specification.
Requests
A single function is generated for each endpoint. It returns an HttpRequest result.
Resources
A single function is generated for each endpoint. It returns a result from httpResource call.
Web Src Content Docs Docs Openapi Typescript Plugins Concepts Resolvers (`web/src/content/docs/docs/openapi/typescript/plugins/concepts/resolvers.mdx`)
title: Resolvers
import { Tabs, TabItem } from '@astrojs/starlight/components';
Resolvers
Sometimes the default plugin behavior isn't what you need or expect. Resolvers let you patch plugins in a safe and performant way, without forking or reimplementing core logic.
Currently available for TypeScript, Valibot, and Zod.
Examples
This page demonstrates resolvers through a few common scenarios.
- Handle arbitrary schema formats
- Validate high precision numbers
- Replace default base
- Create permissive enums
Terminology
Before we look at examples, let's go through the resolvers API to help you understand how they work. Plugins that support resolvers expose them through the $resolvers option. Each resolver is a function that receives context and returns an implemented node (or patches existing ones).
The resolver context will usually contain:
$- The node builder interface. Use it to build your custom logic.nodes- Parts of the plugin logic. You can use these to avoid reimplementing the functionality, or replace them with custom implementation.plugin- The plugin instance. You'll most likely use it to register new symbols.symbols- Frequently used symbols. These are effectively shorthands for commonly usedplugin.referenceSymbol()calls.
Other fields may include the current schema or relevant utilities.
Example 1
Handle arbitrary schema formats
By default, the Valibot plugin may produce the following schemas for date and date-time strings.
export const vDates = v.object({
created: v.pipe(v.string(), v.isoDate()),
modified: v.pipe(v.string(), v.isoTimestamp()),
});We can override this behavior by patching the nodes.format function only for strings with date or date-time formats.
{
name: 'valibot',
$resolvers: {
string(ctx) {
const { $, schema, symbols } = ctx;
const { v } = symbols;
if (schema.format === 'date' || schema.format === 'date-time') {
ctx.nodes.format = () => $(v).attr('isoDateTime').call();
}
}
}
}This applies custom logic with surgical precision, without affecting the rest of the default behavior.
Example 2
Validate high precision numbers
Let's say you're dealing with very large or unsafe numbers.
export const vAmount = v.number();In this case, you'll want to use a third-party library to validate your values. We can use big.js to validate all numbers by replacing the whole resolver.
{
name: 'valibot',
$resolvers: {
number(ctx) {
const { $, plugin, symbols } = ctx;
const { v } = symbols;
const big = plugin.symbolOnce('Big', {
external: 'big.js',
importKind: 'default',
});
return $(v).attr('instance').call(big);
}
}
}We're calling plugin.symbolOnce() to ensure we always use the same symbol reference.
export const vAmount = v.instance(Big);
</TabItem>
<TabItem label="before">
```js title="valibot.gen.ts"
export const vAmount = v.number();Example 3
Replace default base
You might want to replace the default base schema, e.g., v.object().
export const vUser = v.object({
age: v.number(),
});Let's say we want to interpret any schema without explicitly defined additional properties as a loose object.
{
name: 'valibot',
$resolvers: {
object(ctx) {
const { $, symbols } = ctx;
const { v } = symbols;
const additional = ctx.nodes.additionalProperties(ctx);
if (additional === undefined) {
const shape = ctx.nodes.shape(ctx);
ctx.nodes.base = () => $(v).attr('looseObject').call(shape);
}
}
}
}Above we demonstrate patching a node based on the result of another node.
Example 4
Create permissive enums
By default, enum schemas are strict and will reject unknown values.
export const zStatus = z.enum(['active', 'inactive', 'pending']);You might want to accept unknown enum values, for example when the API adds new values that haven't been added to the spec yet. You can use the enum resolver to create a permissive union.
{
name: 'zod',
$resolvers: {
enum(ctx) {
const { $, symbols } = ctx;
const { z } = symbols;
const { enumMembers, literalSchemas } = ctx.nodes.items(ctx);
if (!enumMembers.length || enumMembers.length !== literalSchemas.length) {
return;
}
const enumSchema = $(z).attr('enum').call($.array(...enumMembers));
return $(z).attr('union').call(
$.array(enumSchema, $(z).attr('string').call())
);
}
}
}This resolver creates a union that accepts both the known enum values and any other string.
Feedback
We welcome feedback on the Resolvers API. Open a GitHub issue to request support for additional plugins.
Web Src Content Docs Docs Openapi Typescript Plugins Orpc V1 (`web/src/content/docs/docs/openapi/typescript/plugins/orpc/v1.mdx`)
title: oRPC v1 Plugin sidebar: label: oRPC custom: version: v1
import { Tabs, TabItem } from '@astrojs/starlight/components';
import AuthorsList from '@/components/AuthorsList.astro';
import Examples from '@/components/Examples.astro';
import FeatureStatus from '@/components/FeatureStatus.astro';
import UserConfig from '@/components/UserConfig.astro';
import { stephenZhou } from '@/data/people';
oRPC
About
oRPC combines RPC with OpenAPI, allowing you to define and call remote or local procedures through a type-safe API while adhering to the OpenAPI specification.
The oRPC plugin for Hey API generates contracts from your OpenAPI spec, fully compatible with all core features.
Collaborators
Features
- oRPC v1 support
- seamless integration with
@hey-api/openapi-tsecosystem - generated contracts
- minimal learning curve thanks to extending the underlying technology
Installation
In your configuration, add orpc to your plugins and you'll be ready to generate oRPC artifacts. 🎉
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
'orpc',
],
};Output
The oRPC plugin will generate the following artifacts, depending on the input specification.
Contracts
Contracts are generated from all endpoints.
const addPet = oc.route({
description: 'Add a new pet to the store.',
inputStructure: 'detailed',
method: 'POST',
operationId: 'addPet',
path: '/pet',
summary: 'Add a new pet to the store.',
tags: ['pet'],
});
</TabItem>
<TabItem label="config">
```js title="openapi-ts.config.ts"
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
'orpc',
],
};Validators
To enable schema validation, set validator to zod or one of the available validator plugins. This will automatically add the selected plugin with its default configuration.
For a more granular approach, manually add a validator plugin and set validator to the plugin name or true to automatically select a compatible plugin. Until you customize the validator plugin, both approaches will produce the same default output.
import { vAddPetBody, vAddPetResponse } from './valibot.gen';
const addPet = oc
.route({
description: 'Add a new pet to the store.',
inputStructure: 'detailed',
method: 'POST',
operationId: 'addPet',
path: '/pet',
summary: 'Add a new pet to the store.',
tags: ['pet'],
})
.input(v.object({ body: vAddPetBody }))
.output(vAddPetResponse);
</TabItem>
<TabItem label="config">
```js {8,11} title="openapi-ts.config.ts"
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
{
name: 'orpc',
validator: true, // or 'valibot'
},
{
name: 'valibot', // customize (optional)
// other options
},
],
};You can choose to validate only inputs or outputs.
Learn more about available validators on the Validators page.
Web Src Content Docs Docs Openapi Typescript Plugins Orpc V2 (`web/src/content/docs/docs/openapi/typescript/plugins/orpc/v2.mdx`)
title: oRPC v2 Plugin sidebar: label: oRPC custom: version: v2
import { Tabs, TabItem } from '@astrojs/starlight/components';
import AuthorsList from '@/components/AuthorsList.astro';
import Examples from '@/components/Examples.astro';
import FeatureStatus from '@/components/FeatureStatus.astro';
import UserConfig from '@/components/UserConfig.astro';
import { stephenZhou } from '@/data/people';
oRPC
About
oRPC combines RPC with OpenAPI, allowing you to define and call remote or local procedures through a type-safe API while adhering to the OpenAPI specification.
The oRPC plugin for Hey API generates contracts from your OpenAPI spec, fully compatible with all core features.
Collaborators
Features
- oRPC v2 support
- seamless integration with
@hey-api/openapi-tsecosystem - generated contracts
- minimal learning curve thanks to extending the underlying technology
Installation
In your configuration, add orpc to your plugins and you'll be ready to generate oRPC artifacts. 🎉
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
{
name: 'orpc',
compatibilityVersion: '2',
},
],
};Output
The oRPC plugin will generate the following artifacts, depending on the input specification.
Contracts
Contracts are generated from all endpoints.
const addPet = oc.meta(
openapi({
description: 'Add a new pet to the store.',
inputStructure: 'detailed',
method: 'POST',
operationId: 'addPet',
path: '/pet',
summary: 'Add a new pet to the store.',
tags: ['pet'],
}),
);
</TabItem>
<TabItem label="config">
```js title="openapi-ts.config.ts"
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
{
name: 'orpc',
compatibilityVersion: '2',
},
],
};Query Styles
When generating oRPC v2 contracts, queryStyles metadata is inferred by default for OpenAPI serialization styles supported by oRPC, so arrays and delimited objects keep their original serialization behavior.
const getItems = oc.meta(
openapi({
inputStructure: 'detailed',
method: 'GET',
operationId: 'getItems',
path: '/items',
queryStyles: {
ids: 'array',
filters: 'comma-delimited-object',
tags: 'comma-delimited-array',
},
tags: ['items'],
}),
);You can disable this metadata when you want oRPC's default bracket notation.
oRPC does not currently expose a queryStyles value for form-exploded objects, so those parameters use oRPC's default bracket notation.
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
{
compatibilityVersion: '2',
inferQueryStyles: false,
name: 'orpc',
},
],
};Validators
To enable schema validation, set validator to zod or one of the available validator plugins. This will automatically add the selected plugin with its default configuration.
For a more granular approach, manually add a validator plugin and set validator to the plugin name or true to automatically select a compatible plugin. Until you customize the validator plugin, both approaches will produce the same default output.
import { vAddPetBody, vAddPetResponse } from './valibot.gen';
const addPet = oc
.meta(
openapi({
description: 'Add a new pet to the store.',
inputStructure: 'detailed',
method: 'POST',
operationId: 'addPet',
path: '/pet',
summary: 'Add a new pet to the store.',
tags: ['pet'],
}),
)
.input(v.object({ body: vAddPetBody }))
.output(vAddPetResponse);
</TabItem>
<TabItem label="config">
```js {9,12} title="openapi-ts.config.ts"
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
{
compatibilityVersion: '2',
name: 'orpc',
validator: true, // or 'valibot'
},
{
name: 'valibot', // customize (optional)
// other options
},
],
};You can choose to validate only inputs or outputs.
Learn more about available validators on the Validators page.
Web Src Content Docs Docs Openapi Typescript Plugins Zod Mini (`web/src/content/docs/docs/openapi/typescript/plugins/zod/mini.mdx`)
title: Zod Mini Plugin custom: version: Mini versionSynonym: v4
import { Tabs, TabItem } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';
import UserConfig from '@/components/UserConfig.astro';
Zod
About
Zod is a TypeScript-first schema validation library with static type inference.
The Zod plugin for Hey API generates schemas from your OpenAPI spec, fully compatible with validators, transformers, and all core features.
Features
- Zod Mini support
- seamless integration with
@hey-api/openapi-tsecosystem - Zod schemas for requests, responses, and reusable definitions
- minimal learning curve thanks to extending the underlying technology
Installation
In your configuration, add zod to your plugins and you'll be ready to generate Zod artifacts. 🎉
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
{
name: 'zod',
compatibilityVersion: 'mini',
},
],
};SDKs
Zod can validate or transform data directly in your SDK. Set validator or transformer to true on the SDK plugin to enable it.
The SDK page covers validators and transformers in more detail.
Output
The Zod plugin will generate the following artifacts, depending on the input specification.
Requests
A Zod schema is generated for every request layer of each endpoint.
const zDeletePetPath = z.object({
petId: z.number(),
});
const zDeletePetQuery = z.object({
additionalMetadata: z.string(),
});
</TabItem>
<TabItem label="config">
```js {9} title="openapi-ts.config.ts"
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
{
name: 'zod',
compatibilityVersion: 'mini',
requests: true,
},
],
};You can customize the naming and casing pattern for requests schemas using the .name and .case options.
Responses
A single Zod schema is generated for all endpoint's responses. If the endpoint describes multiple responses, the generated schema is a union of all possible response shapes.
You can customize the naming and casing pattern for responses schemas using the .name and .case options.
Definitions
A Zod schema is generated for every reusable definition from your input.
const zBar = z.object({
bar: z.optional(z.array(z.int())),
});
</TabItem>
<TabItem label="config">
```js {9} title="openapi-ts.config.ts"
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
{
name: 'zod',
compatibilityVersion: 'mini',
definitions: true,
},
],
};You can customize the naming and casing pattern for definitions schemas using the .name and .case options.
ISO Datetimes
By default, values without a timezone or with a timezone offset are not allowed in the z.iso.datetime() method.
Timezone offsets
You can allow values with timezone offsets by setting dates.offset to true.
Local times
You can allow values without a timezone by setting dates.local to true.
Metadata
It's often useful to associate a schema with some additional metadata for documentation, code generation, AI structured outputs, form validation, and other purposes. You can set metadata to true to attach descriptions to schemas when available.
For more control over metadata, you can provide your own function. It receives the source schema, the target node object, and the $ builder for populating metadata.
Types
In addition to Zod schemas, you can generate schema-specific types. These can be generated for all schemas or for specific resources.
You can customize the naming and casing pattern for schema-specific types using the .name and .case options.
Resolvers
You can further customize this plugin's behavior using resolvers.
Web Src Content Docs Docs Openapi Typescript Plugins Zod V3 (`web/src/content/docs/docs/openapi/typescript/plugins/zod/v3.mdx`)
title: Zod v3 Plugin custom: version: v3
import { Tabs, TabItem } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';
import UserConfig from '@/components/UserConfig.astro';
Zod
About
Zod is a TypeScript-first schema validation library with static type inference.
The Zod plugin for Hey API generates schemas from your OpenAPI spec, fully compatible with validators, transformers, and all core features.
Features
- Zod v3 support
- seamless integration with
@hey-api/openapi-tsecosystem - Zod schemas for requests, responses, and reusable definitions
- minimal learning curve thanks to extending the underlying technology
Installation
In your configuration, add zod to your plugins and you'll be ready to generate Zod artifacts. 🎉
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
{
name: 'zod',
compatibilityVersion: 3,
},
],
};SDKs
Zod can validate or transform data directly in your SDK. Set validator or transformer to true on the SDK plugin to enable it.
The SDK page covers validators and transformers in more detail.
Output
The Zod plugin will generate the following artifacts, depending on the input specification.
Requests
A Zod schema is generated for every request layer of each endpoint.
const zDeletePetPath = z.object({
petId: z.number(),
});
const zDeletePetQuery = z.object({
additionalMetadata: z.string(),
});
</TabItem>
<TabItem label="config">
```js {9} title="openapi-ts.config.ts"
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
{
name: 'zod',
compatibilityVersion: 3,
requests: true,
},
],
};You can customize the naming and casing pattern for requests schemas using the .name and .case options.
Responses
A single Zod schema is generated for all endpoint's responses. If the endpoint describes multiple responses, the generated schema is a union of all possible response shapes.
You can customize the naming and casing pattern for responses schemas using the .name and .case options.
Definitions
A Zod schema is generated for every reusable definition from your input.
const zBar = z.object({
bar: z.array(z.number().int()).optional(),
});
</TabItem>
<TabItem label="config">
```js {9} title="openapi-ts.config.ts"
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
{
name: 'zod',
compatibilityVersion: 3,
definitions: true,
},
],
};You can customize the naming and casing pattern for definitions schemas using the .name and .case options.
ISO Datetimes
By default, values without a timezone or with a timezone offset are not allowed in the z.string().datetime() method.
Timezone offsets
You can allow values with timezone offsets by setting dates.offset to true.
Local times
You can allow values without a timezone by setting dates.local to true.
Metadata
It's often useful to associate a schema with some additional metadata for documentation, code generation, AI structured outputs, form validation, and other purposes. If this is your use case, you can set metadata to true to generate additional metadata about schemas.
Types
In addition to Zod schemas, you can generate schema-specific types. These can be generated for all schemas or for specific resources.
You can customize the naming and casing pattern for schema-specific types using the .name and .case options.
Resolvers
You can further customize this plugin's behavior using resolvers.
Web Src Content Docs Docs Openapi Typescript Plugins Zod V4 (`web/src/content/docs/docs/openapi/typescript/plugins/zod/v4.mdx`)
title: Zod v4 Plugin sidebar: label: Zod custom: version: v4
import { Tabs, TabItem } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';
import UserConfig from '@/components/UserConfig.astro';
Zod
About
Zod is a TypeScript-first schema validation library with static type inference.
The Zod plugin for Hey API generates schemas from your OpenAPI spec, fully compatible with validators, transformers, and all core features.
Features
- Zod v4 support
- seamless integration with
@hey-api/openapi-tsecosystem - Zod schemas for requests, responses, and reusable definitions
- minimal learning curve thanks to extending the underlying technology
Installation
In your configuration, add zod to your plugins and you'll be ready to generate Zod artifacts. 🎉
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
'zod',
],
};SDKs
Zod can validate or transform data directly in your SDK. Set validator or transformer to true on the SDK plugin to enable it.
The SDK page covers validators and transformers in more detail.
Output
The Zod plugin will generate the following artifacts, depending on the input specification.
Requests
A Zod schema is generated for every request layer of each endpoint.
const zDeletePetPath = z.object({
petId: z.number(),
});
const zDeletePetQuery = z.object({
additionalMetadata: z.string(),
});
</TabItem>
<TabItem label="config">
```js {8} title="openapi-ts.config.ts"
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
{
name: 'zod',
requests: true,
},
],
};You can customize the naming and casing pattern for requests schemas using the .name and .case options.
Responses
A single Zod schema is generated for all endpoint's responses. If the endpoint describes multiple responses, the generated schema is a union of all possible response shapes.
You can customize the naming and casing pattern for responses schemas using the .name and .case options.
Definitions
A Zod schema is generated for every reusable definition from your input.
const zBar = z.object({
bar: z.optional(z.array(z.int())),
});
</TabItem>
<TabItem label="config">
```js {8} title="openapi-ts.config.ts"
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
{
name: 'zod',
definitions: true,
},
],
};You can customize the naming and casing pattern for definitions schemas using the .name and .case options.
ISO Datetimes
By default, values without a timezone or with a timezone offset are not allowed in the z.iso.datetime() method.
Timezone offsets
You can allow values with timezone offsets by setting dates.offset to true.
Local times
You can allow values without a timezone by setting dates.local to true.
Metadata
It's often useful to associate a schema with some additional metadata for documentation, code generation, AI structured outputs, form validation, and other purposes. You can set metadata to true to attach descriptions to schemas when available.
For more control over metadata, you can provide your own function. It receives the source schema, the target node object, and the $ builder for populating metadata.
Types
In addition to Zod schemas, you can generate schema-specific types. These can be generated for all schemas or for specific resources.
You can customize the naming and casing pattern for schema-specific types using the .name and .case options.
Resolvers
You can further customize this plugin's behavior using resolvers.
--- METRICS ---
- Files Extracted: 111
- Estimated Token Budget: ~119442 tokens
- Canonical Reference: https://codewiki.google/github.com/hey-api/openapi-ts