Client
Officialv6.0.4@kubb/plugin-client
Migrate to v6
Update your client module for @kubb/plugin-client 6, which calls your client with type arguments and streams through client.stream.
What to change
| Your code | What to do |
|---|---|
Exports a client that takes no type arguments | Make it generic. |
Exports toEventStream or EventStreamResult | Add a stream method. |
Declares responseType on RequestConfig, or lacks contentType or cookies | Add the new fields. |
Reads security entries as single schemes | Handle arrays and the new fields. |
Imports a …Status2XX type, or writes a '2XX' key | Write ranges in lower case. |
Groups by tag in an OpenAPI 3.2 document whose tags set parent | Update the import paths. |
Has servers on a path or operation, or reads XML, YAML, CSV, or binary bodies | It compiles. Check the behavior changes. |
Wants .unwrap() or a call that resolves to the body | Optional. Set returnType. |
Upgrade steps
Upgrade
kubband@kubb/plugin-clienttogether. v6 needs Kubb 5.19.0 or later:npm install --save-dev kubb@latest @kubb/plugin-client@6- Update your client module with the sections below.
- Regenerate with
npx kubb generate. - Run
npx tsc --noEmit. A missing export or field shows up as a compile error in the generated files.
A generic client call
A generated function calls client<TResponses, ThrowOnError>(config):
export const client = <TResponses, ThrowOnError extends boolean = true>(config: RequestConfig) =>
send(config) as Promise<RequestResult<TResponses, ThrowOnError>>A stream method instead of toEventStream
A Server-Sent Events or JSON Lines operation calls client.stream<TResponses, ThrowOnError, TItem>(config). Remove toEventStream and EventStreamResult, add stream to client, and export StreamResult, SuccessOf, TypedEvent, and ServerSentEvent:
export type StreamResult<TResponses, ThrowOnError extends boolean = true, TEvent = ServerSentEvent<SuccessOf<TResponses>>> = {
stream: AsyncGenerator<TEvent>
response: Response
}
export function client<TResponses, ThrowOnError extends boolean = true>(config: RequestConfig) {
return send<TResponses, ThrowOnError>(config)
}
client.stream = async <TResponses, ThrowOnError extends boolean = true, TEvent = ServerSentEvent<SuccessOf<TResponses>>>(
config: RequestConfig,
): Promise<StreamResult<TResponses, ThrowOnError, TEvent>> => {
// send the request and parse the body into TEvent values
}See Stream Server-Sent Events and JSON Lines for every stream field and for JSON Lines.
New fields on the request config
Add these fields to your RequestConfig, or the generated functions fail to compile:
export type RequestConfig = {
// ...
contentType?: string | { request?: string; response?: string }
// Replaces `responseType`. Binary downloads pass 'blob'.
parseAs?: 'json' | 'text' | 'blob' | 'arrayBuffer' | 'stream'
// Server-Sent Events only.
eventShape?: 'event' | 'data'
rawData?: boolean | Array<string>
// Name and value pairs for `in: cookie` parameters. Join them into a `Cookie` header on the server.
cookies?: object
// `style`, `explode`, `allowReserved`, and `contentType` per parameter, grouped by location.
styles?: object
}Cookie header set by script and send their own cookies. See Cookie parameters with the cookie style for the OpenAPI 3.2 cookie style.Security requirements
An entry is an array when one requirement needs several schemes together, such as an API key and a session cookie. Send all of them, or skip the entry. oauth2 now also passes flows and metadataUrl, and openIdConnect passes url:
export type Auth = {
type: string
scheme?: string
name?: string
in?: string
scopes?: Array<string>
flows?: Record<string, Record<string, string>>
metadataUrl?: string
url?: string
}Status ranges
Generated names and keys write status ranges in lower case. Rename the imports and any range keys you wrote by hand in a responses record or validator.error map. An upper-case key such as '2XX' is no longer read:
import type { ListPetsStatus4XX } from './gen/types/ListPets'
import type { ListPetsStatus4xx } from './gen/types/ListPets'Tag folders
With group: { type: 'tag' }, a tag whose OpenAPI 3.2 parent is store now writes to store/payment/, not payment/. One relative importPath cannot serve both folder depths. Pass group.name to keep one folder per tag, or set importPath to a package name or alias:
pluginClient({ importPath: '../../../client', group: { type: 'tag', name: ({ group }) => group } })Behavior changes
These compile without errors, so check them by hand:
| Change | What your client must do |
|---|---|
A path or operation with its own servers passes that server as baseURL. | Use config.baseURL when set. |
A 2xx key is a success, and an exact code such as 200 wins over a range before it. | Nothing, unless you read the responses record by hand. |
XML, YAML, and CSV responses are typed string. Image, audio, video, PDF, and application/octet-stream responses are Blob. | Read a Blob when the call passes parseAs: 'blob', which it does when every success type is binary. |
An operation whose only success type is JSON Lines returns a StreamResult. | Parse one item per line in client.stream. |
Return type
returnType is new and defaults to 'plain', so existing code keeps working. 'full' adds .unwrap(), and 'data' resolves to the body when throwOnError is true. Both 'full' and 'data' import extra helpers from your module. See returnType.
Call operations
Call a generated function with one grouped options object. It returns your client's promise, shaped by your RequestResult type.
Stream Server-Sent Events and JSON Lines
Add client.stream and its types to your client module, so streamed operations compile and yield typed events or lines.
