@beta. For v3, read the docs in the v3 branch.Migrating to v4
v4 replaces @hey-api/openapi-ts with a client generator that ships inside this package. The generated hooks are unchanged — same names, same signatures, same query keys — so for most projects migrating means updating the package, regenerating, and checking the handful of differences below.
-
Use Node.js 24 or later to run the generator (v3 needed 22.18).
-
Update the package and regenerate:
Terminal window npm install -D @7nohe/openapi-react-query-codegen@betanpx openapi-rq -i ./petstore.yaml -
If you pass
-c @hey-api/client-fetchor-c @hey-api/client-axios, both still work. Prefer the new spellings-c fetchand-c axios. -
Delete the stale
client/andcore/folders fromopenapi/requests(the easiest way is to remove the wholeopenapifolder before regenerating). -
Everything else is compatible — you are done.
What stays the same
Section titled “What stays the same”- Every generated hook, prefetch/
ensureQueryDatafunction,queryOptionsfactory, key constant and key function keeps its v3 name and signature. For the same specification the generatedopenapi/queriesfiles differ from v3 only in the order of import specifiers. clientis still exported fromopenapi/requests/client.gen(and from theservices.gencompatibility shim) withsetConfig()andinterceptors.- SDK functions keep the
{ data, error, request, response }result and throw the error whenthrowOnErroris set. The hooks always set it, so failed requests reject (as in v3). --format,--lint,--enums,--noOperationId,--pageParam,--nextPageParam,--initialPageParamand--omitInitialPageParambehave as before.--useDateType,--noSchemasand--schemaTypeare still there. See dates and JSON schemas for the details that differ.
What changed
Section titled “What changed”openapi/requests
Section titled “openapi/requests”| v3 | v4 |
|---|---|
client/, core/ (Hey API runtime) |
runtime.gen.ts (one file) |
client.gen.ts, sdk.gen.ts, types.gen.ts, services.gen.ts, index.ts |
same names |
schemas.gen.ts (JSON schemas) |
same name |
transformers.gen.ts (with --useDateType) |
same name |
Anything that imported from openapi/requests/client or openapi/requests/core needs to import from openapi/requests/runtime.gen instead (for example the Config and Options types).
When your tsconfig.json resolves modules the Node way (node16 or nodenext), relative imports in both openapi/requests and openapi/queries end with .js.
The HTTP runtimes
Section titled “The HTTP runtimes”The runtimes are small, dependency-free TypeScript files generated into your project (axios aside). They cover what the hooks and typical applications use:
baseUrl(baseURLfor axios),headers,throwOnError,signaland any otherfetchoption- request, response and error
interceptors(fetch) orclient.instance.interceptors(axios) authfor operations withsecurity(bearer, basic and API keys in header, query or cookie), including schemes an operation requires togetherquerySerializer,pathSerializerandbodySerializer, with OpenAPIstyle/explodehonoured per query and path parameter- JSON,
multipart/form-data,application/x-www-form-urlencoded, text and binary request bodies; JSON, text, blob, form data and stream responses viaparseAs responseTransformer, called with the data of a successful response- With
parseAs: "auto", the default, XML responses are read as text instead of aBlob, and a response without aContent-Typeas text instead of a stream
Three behaviours differ from v3, each to follow the specification:
- A query parameter whose schema is a
$refto an object and that has nostyleis sent in the OpenAPI default,formwithexplode(role=admin). v3 did this for inline object schemas but sent$refs asfilter[role]=admin. Specifystyle: deepObjectto keep that form. - Path parameters with
style: labelorstyle: matrix, or an exploded object, are serialized as declared. v3 ignored both settings. - With
-c axios, a JSON request body that is a string is always sent as a JSON string. v3 sent a string that happened to parse as JSON, such as"true", as that JSON value.
Not carried over from the Hey API clients: server-sent events, responseStyle, requestValidator/responseValidator, the helpers exported from openapi/requests/client and openapi/requests/core (mergeHeaders, jsonBodySerializer, formDataBodySerializer, urlSearchParamsBodySerializer, buildClientParams, serializeQueryKeyValue), and the runtimeConfigPath option. If you relied on them, keep calling those parts of your API through your own code.
Specification support
Section titled “Specification support”OpenAPI 3.0 and 3.1 are supported, including external $refs to files and URLs. A schema in another file is exported under its own name, as in v3. Swagger/OpenAPI 2.0 documents are rejected with an explicit error — convert them to OpenAPI 3 first.
Naming
Section titled “Naming”-
Operations without an
operationIdare named after the method and path (getPetsById), as before. -
A name that would collide with a schema or another operation's type gets a number appended on its own, instead of producing duplicate identifiers or renaming the whole operation. For example, when the specification has a
ListRunsResponseschema and an operationlistRuns, the schema keeps its name,ListRunsData/ListRunsResponses/ListRunsErrorskeep theirs, and only the alias becomesListRunsResponse2. The hooks keep their names. -
Schema names are converted to PascalCase as in v3 (
account_annual_revenue→AccountAnnualRevenue,FineTuneDPOHyperparameters→FineTuneDpoHyperparameters). -
Operation names and enum members are cased as in v3, acronyms included (
getHTTPStatus→getHttpStatus,useGetHttpStatus,HTTPServer→HTTP_SERVER). -
A digit-leading
operationIdsuch as123numericLeadyields the function_123NumericLeadand the types_123NumericLeadData/_123NumericLeadError(v3 dropped the digits from the types only). -
Some names are taken by what generated code uses, and get a suffix where v3 failed to compile: schemas such as
Options,Array,Promise,OmitorQueryClientbecomeOptions2,Array2and so on, and operations such asclient,options,signal,queryClientoruseQuerybecomeclient_,options_,queryClient_anduseQuery_(their hooks areuseClient_, …). Schemas namedBlobandFilekeep their names, and binary fields refer toglobalThis.BlobandglobalThis.File.
Stricter types
Section titled “Stricter types”A property that an allOf requires is now required in the generated type, wherever it is declared. v3 left it optional when the required list and the declaration were in different members, as in allOf: [{ $ref: Base }, { required: [id] }], so code that reads it gets a narrower type and code that builds such an object has to set it.
A oneOf or anyOf next to an allOf is now part of the type (Base & (A | B)). v3 dropped the union and emitted Base.
In OpenAPI 3.1, a string with a contentMediaType is a file (Blob | File) for every media type that is not text (JSON, XML, text/*, form-urlencoded), unless it also has a contentEncoding such as base64, which makes it a string. v3 knew a fixed list of media types, so image/png was a string, and it ignored contentEncoding for application/octet-stream.
Types that are no longer generated
Section titled “Types that are no longer generated”v3 emitted a few helper types that no hook uses. They are gone in v4; if your code imports one, declare it yourself from the schema:
- types for
components.parameters(for examplePagefor aPageparameter) and for webhooks (Webhooks,…WebhookRequest) *Writablealiases of schemas that have noreadOnly/writeOnlyproperty. A real request-side variant (PetWritable, without thereadOnlyproperties) is still generated, and the type of areadOnlyproperty is nowreadonlyin response types.
Types for components.requestBodies are still generated (Pet2 and UserArray for the Petstore). Two details differ: an operation's body refers to the schema itself rather than to the request body's type, and when a request body shares its name with a schema or an operation's type, the request body is the one that gets the number.
Two typing differences to be aware of: a fixed-length array (minItems equal to maxItems) is a tuple, as before, and when prefixItems is followed by items the remaining elements are typed as ...Array<T> rather than one extra tuple member. oneOf/anyOf members with a discriminator are narrowed by the discriminator value unless the member already pins the property to literals; without a mapping, the value is the schema's name as written in the specification (Zoo.Cat, where v3 wrote Zoo_Cat). In OpenAPI 3.1, keywords next to a $ref (properties, required, …) now apply together with the reference, while OpenAPI 3.0 keeps ignoring them as the specification says. A type on its own next to a $ref is not applied, as in v3.
Performance
Section titled “Performance”Large specifications generate much faster, mostly because the hook files now import only the models they use: the 4 MB OpenAI specification (388 operations) takes about 5 seconds instead of about 30.
Dates and JSON schemas
Section titled “Dates and JSON schemas”--useDateType, --noSchemas and --schemaType work as in v3, without the Hey API plugins they used to hand over to.
--useDateType
Section titled “--useDateType”date and date-time strings are typed Date, in responses and in what you send, and transformers.gen.ts turns them into Date objects in successful responses. Three details differ from v3:
- A
oneOf/anyOfis converted wherever its members can be told apart: by their shape (a date next tonull, a number, an object or an array), or by adiscriminator. v3 converted a union only when it was a single schema next tonull. - When two members of a union are both objects, or both arrays, and no
discriminatortells them apart, their dates stay strings, as in v3. The generator prints each such place. - The transformer runs on every successful response, not only on the ones read as JSON. A value that is not what the schema describes is passed on as it came.
As in v3, error responses are not converted: an error body keeps its date strings although its type says Date.
schemas.gen.ts
Section titled “schemas.gen.ts”The constants have the names v3 gave them (PetSchema, my_schemaSchema, PetWritableSchema) and hold the schemas as the specification writes them. One detail differs: a schema that is only a $ref to another one (Alias: { $ref: "#/components/schemas/Pet" }) stays a reference where other schemas point at it. v3 rewrote those references to the target.
Dependency changes
Section titled “Dependency changes”- Node.js 24 or later is required (
engines.nodeis>=24.0.0; v3 needed 22.18). This is the version that runsopenapi-rq. The generated code has no Node.js requirement of its own. @hey-api/openapi-tsis no longer a dependency, so its (FSL) license no longer applies to your install.yaml(exact-pinned, no dependencies of its own) was added to parse YAML specifications.typescriptis no longer a peer dependency, so the TypeScript version of your project cannot conflict with this package, and TypeScript 7 works. The generator reads yourtsconfig.jsonitself (comments, trailing commas andextendsincluded) to decide whether relative imports need.js, instead of using the TypeScript compiler API, which version 7 does not have. The generated code compiles with TypeScript 5.x, 6.x and 7.x.ts-morphis no longer a peer dependency. If you installed it only for this package, you can remove it. The hook files are now printed directly, which makes generation faster on large specifications.- The remaining peer dependencies (
@tanstack/react-query,commander) are unchanged.axiosis needed in your project only with-c axios.