Call operations
@kubb/plugin-fetch and @kubb/plugin-axios turn each operation in your OpenAPI spec into a
typed function. The two plugins generate different transports but share one calling convention, so
the code on this page reads the same whichever you pick. Swap the import and the examples still
hold.
Every operation takes a single grouped options object and returns one RequestResult. The
parameters are typed from the spec, and the result carries the status, the parsed body, and the
native request and response.
Call an operation
Import the generated function and pass the parameters it declares. Kubb groups them by where they
belong in the request: path, query, headers, cookies, and body.
import { getPetById } from './gen/clients/getPetById'
const { data } = await getPetById({ path: { petId: 1 } })
// ^ the parsed pet, typed from the 200 responseA path like /pets/{petId}/photos/{photoId} takes each segment under path:
import { getPetPhoto } from './gen/clients/getPetPhoto'
const { data } = await getPetPhoto({
path: { petId: '123', photoId: '456' },
})Query, header, and cookie parameters sit under their own keys, and a request body goes under
body:
import { searchPets } from './gen/clients/searchPets'
import { updatePet } from './gen/clients/updatePet'
await searchPets({
query: { status: 'available', category: 'dogs', limit: 10, offset: 0 },
})
await updatePet({
path: { petId: '123' },
headers: { 'X-Request-ID': 'req-123456' },
body: { name: 'Updated name', status: 'sold' },
})Each key is optional and only appears when the operation declares it, so an operation with no
parameters is called with an empty object, getStatus({}). How Kubb encodes arrays and objects in
each location is covered in serialization.
Read the result
A resolved call returns a RequestResult discriminated by the numeric status:
type RequestResult = {
status: number
data: TData // the parsed success body, undefined on an error result
error: TError // the parsed error body, undefined on a success result
contentType: string | undefined // the negotiated response media type
request: Request // the native request (AxiosRequestConfig on plugin-axios)
response: Response // the native response (AxiosResponse on plugin-axios)
}With the default throwOnError, a resolved call is always a success, so you read data
straight away:
const { data, status, response } = await getPetById({ path: { petId: 1 } })
console.info(status) // 200
console.info(response.headers.get('x-ratelimit-remaining'))When an operation documents more than one success status, narrow on status to reach the body
for that case. TypeScript follows the check:
const result = await getPetById({ path: { petId: 1 } })
if (result.status === 200) {
console.info(result.data.name)
}Reading the error body and handling failures is covered in
error handling.
Set the content type
When an operation accepts or returns more than one media type, set contentType on the call. A
bare string sets the request content type. The object form also sends an Accept header for the
response:
await uploadAvatar({
path: { petId: '123' },
body: avatarBlob,
contentType: 'image/png',
})
await getPet({
path: { petId: '123' },
contentType: { request: 'application/json', response: 'application/xml' },
})For operations that already declare a single content type, Kubb bakes it into the generated function, so a multipart upload needs only the body:
import { uploadFile } from './gen/clients/uploadFile'
// the generated function already sets contentType: { request: 'multipart/form-data' }
await uploadFile({ path: { petId: '123' }, body: { file: pngBlob } })How each content type maps to a request body, and how a response body is decoded, lives in serialization.
Reuse one configuration
Every generated function imports a shared client. Call setConfig once at startup and every
call picks up the change:
import { client } from './gen/clients/.kubb/client'
client.setConfig({
baseURL: 'https://api.example.com/v1',
headers: { 'X-Client': 'web' },
})For an isolated client that does not touch the shared one, build a separate instance with
createClient and pass it on the client option of any call. This suits tests and talking to
more than one backend:
import { createClient } from './gen/clients/.kubb/client'
import { getPetById } from './gen/clients/getPetById'
const staging = createClient({ baseURL: 'https://staging.example.com/v1' })
await getPetById({ path: { petId: 1 }, client: staging })The configuration object is the same ClientConfig in both cases. baseURL, auth, and the
transport each have their own guide, linked below.
Build a URL without sending
client.getUrl returns the URL for a call without making the request. It runs the same
baseURL, path interpolation, and query serialization as the send path, so it suits building a
link or logging the target ahead of a request:
import { client } from './gen/clients/.kubb/client'
const url = client.getUrl({
url: '/pets/{petId}',
path: { petId: 1 },
query: { fields: 'name' },
})
// https://api.example.com/v1/pets/1?fields=name