The Ky client wraps the popular Ky library, providing a lightweight alternative to Axios with automatic retry, timeout, and hooks built on the native Fetch API.
Installation
npm install @hey-api/client-ky ky
Ky is a peer dependency and must be installed separately.
Basic Usage
Create a client instance
import { createClient } from '@hey-api/client-ky' ;
const client = createClient ({
baseUrl: 'https://api.example.com' ,
});
Make API calls
const { data , error } = await client . get ({
url: '/users/{id}' ,
path: { id: 123 },
});
if ( error ) {
console . error ( 'Error:' , error );
} else {
console . log ( 'User:' , data );
}
Configuration
The Ky client extends Ky configuration with OpenAPI TypeScript features:
Client Options
import { createClient } from '@hey-api/client-ky' ;
import ky from 'ky' ;
const client = createClient ({
// Base URL for all requests
baseUrl: 'https://api.example.com' ,
// Custom Ky instance (optional)
ky: ky . create ({
timeout: 5000 ,
}),
// Default headers
headers: {
'Content-Type' : 'application/json' ,
'X-API-Key' : 'your-api-key' ,
},
// Response parsing format
parseAs: 'json' , // 'json' | 'text' | 'blob' | 'arrayBuffer' | 'formData' | 'stream' | 'auto'
// Response style
responseStyle: 'fields' , // 'fields' | 'data'
// Error handling
throwOnError: false ,
// Timeout (milliseconds)
timeout: 10000 ,
// Retry configuration
retry: {
limit: 2 ,
methods: [ 'get' , 'put' , 'head' , 'delete' , 'options' , 'trace' ],
statusCodes: [ 408 , 413 , 429 , 500 , 502 , 503 , 504 ],
},
// Authentication
auth : async ( auth ) => getToken (),
// Body serialization
bodySerializer : ( body ) => JSON . stringify ( body ),
// Query serialization
querySerializer: {
array: { style: 'form' , explode: true },
object: { style: 'deepObject' , explode: true },
},
// Request validator
requestValidator : async ( data ) => validateRequest ( data ),
// Response transformer
responseTransformer : async ( data ) => transformResponse ( data ),
// Response validator
responseValidator : async ( data ) => validateResponse ( data ),
// Additional Ky options
kyOptions: {
throwHttpErrors: false ,
retry: 0 ,
},
// Standard fetch options
credentials: 'include' ,
mode: 'cors' ,
cache: 'default' ,
});
Custom Ky Instance
Use an existing Ky instance:
import { createClient } from '@hey-api/client-ky' ;
import ky from 'ky' ;
// Create custom Ky instance
const kyInstance = ky . create ({
timeout: 5000 ,
headers: {
'X-Custom-Header' : 'value' ,
},
hooks: {
beforeRequest: [
( request ) => {
console . log ( 'Request:' , request . url );
},
],
},
});
// Use with OpenAPI TypeScript client
const client = createClient ({
baseUrl: 'https://api.example.com' ,
ky: kyInstance ,
});
HTTP Methods
GET
POST
PUT
PATCH
DELETE
const { data , error , response } = await client . get ({
url: '/users' ,
query: {
page: 1 ,
limit: 10 ,
},
});
if ( ! error ) {
console . log ( 'Users:' , data );
console . log ( 'Status:' , response . status );
}
const { data , error } = await client . post ({
url: '/users' ,
body: {
name: 'John Doe' ,
email: '[email protected] ' ,
},
});
const { data } = await client . put ({
url: '/users/{id}' ,
path: { id: 123 },
body: {
name: 'Jane Doe' ,
},
});
const { data } = await client . patch ({
url: '/users/{id}' ,
path: { id: 123 },
body: {
email: '[email protected] ' ,
},
});
const { data } = await client . delete ({
url: '/users/{id}' ,
path: { id: 123 },
});
Retry Configuration
Ky has built-in retry support:
Default Retry
const client = createClient ({
baseUrl: 'https://api.example.com' ,
retry: {
limit: 2 , // Maximum retry attempts
methods: [ 'get' , 'put' , 'head' , 'delete' , 'options' , 'trace' ],
statusCodes: [ 408 , 413 , 429 , 500 , 502 , 503 , 504 ],
},
});
Custom Retry Logic
const client = createClient ({
baseUrl: 'https://api.example.com' ,
kyOptions: {
retry: {
limit: 3 ,
methods: [ 'get' , 'post' ],
statusCodes: [ 408 , 413 , 429 , 500 , 502 , 503 , 504 ],
afterStatusCodes: [ 413 , 429 , 503 ],
},
},
});
Per-Request Retry
const { data } = await client . get ({
url: '/users' ,
retry: {
limit: 5 ,
statusCodes: [ 429 , 503 ],
},
});
Timeout Configuration
Global Timeout
const client = createClient ({
baseUrl: 'https://api.example.com' ,
timeout: 10000 , // 10 seconds
});
Per-Request Timeout
const { data } = await client . get ({
url: '/users' ,
timeout: 5000 , // 5 seconds
});
Disable Timeout
const { data } = await client . get ({
url: '/users' ,
timeout: false ,
});
Response Styles
Fields Style (Default)
const { data , error , request , response } = await client . get ({
url: '/users' ,
responseStyle: 'fields' ,
});
if ( error ) {
console . error ( 'Error:' , error );
} else {
console . log ( 'Data:' , data );
console . log ( 'Status:' , response . status );
}
Data Style
const data = await client . get ({
url: '/users' ,
responseStyle: 'data' ,
});
if ( data ) {
console . log ( 'Users:' , data );
}
Authentication
Bearer Token
const client = createClient ({
baseUrl: 'https://api.example.com' ,
auth : async ( auth ) => {
if ( auth . scheme === 'bearer' ) {
return await getAccessToken ();
}
},
});
API Key
const client = createClient ({
baseUrl: 'https://api.example.com' ,
auth : async ( auth ) => {
if ( auth . type === 'apiKey' ) {
return process . env . API_KEY ;
}
},
});
// Per-request security
const { data } = await client . get ({
url: '/protected' ,
security: [
{
type: 'apiKey' ,
in: 'header' ,
name: 'X-API-Key' ,
},
],
});
Interceptors
Add request, response, and error interceptors:
Request Interceptor
client . interceptors . request . use (( request , options ) => {
console . log ( 'Request:' , request . url );
// Add custom header
request . headers . set ( 'X-Request-ID' , generateRequestId ());
return request ;
});
Response Interceptor
client . interceptors . response . use (( response , request , options ) => {
console . log ( 'Response:' , response . status );
return response ;
});
Error Interceptor
client . interceptors . error . use (( error , response , request , options ) => {
if ( response ?. status === 429 ) {
console . warn ( 'Rate limited, will retry...' );
}
return error ;
});
Server-Sent Events
Stream real-time data:
const stream = await client . sse . get ({
url: '/events' ,
onSseEvent : ( event ) => {
console . log ( 'Event:' , event . data );
},
onSseError : ( error ) => {
console . error ( 'Stream error:' , error );
},
sseMaxRetryAttempts: 3 ,
sseMaxRetryDelay: 5000 ,
});
// Close the stream
stream . close ();
Request Cancellation
const controller = new AbortController ();
const promise = client . get ({
url: '/users' ,
signal: controller . signal ,
});
// Cancel the request
controller . abort ();
Response Parsing
Auto (Default)
const { data } = await client . get ({
url: '/users' ,
parseAs: 'auto' , // Infers from Content-Type
});
// JSON
const { data } = await client . get ({
url: '/users' ,
parseAs: 'json' ,
});
// Text
const { data } = await client . get ({
url: '/document' ,
parseAs: 'text' ,
});
// Blob
const { data } = await client . get ({
url: '/image.png' ,
parseAs: 'blob' ,
});
// Stream
const { data } = await client . get ({
url: '/large-file' ,
parseAs: 'stream' ,
});
Advanced Features
Preflight Requests
import { createClient } from '@hey-api/client-ky' ;
import ky from 'ky' ;
const kyInstance = ky . create ({
hooks: {
beforeRequest: [
async ( request , options ) => {
// Send preflight request
await fetch ( request . url , { method: 'OPTIONS' });
},
],
},
});
const client = createClient ({
baseUrl: 'https://api.example.com' ,
ky: kyInstance ,
});
Response Hooks
import ky from 'ky' ;
const kyInstance = ky . create ({
hooks: {
afterResponse: [
async ( request , options , response ) => {
// Log response time
const responseTime = response . headers . get ( 'X-Response-Time' );
console . log ( 'Response time:' , responseTime );
return response ;
},
],
},
});
const client = createClient ({
baseUrl: 'https://api.example.com' ,
ky: kyInstance ,
});
Error Hooks
import ky from 'ky' ;
import { HTTPError } from 'ky' ;
const kyInstance = ky . create ({
hooks: {
beforeError: [
( error ) => {
const { response } = error ;
if ( response && response . body ) {
error . message = ` ${ error . message } ( ${ response . status } )` ;
}
return error ;
},
],
},
});
TypeScript Types
import type {
Client ,
Config ,
RequestOptions ,
RequestResult ,
ResponseStyle ,
RetryOptions ,
} from '@hey-api/client-ky' ;
// Custom retry configuration
const retryConfig : RetryOptions = {
limit: 3 ,
methods: [ 'get' , 'post' ],
statusCodes: [ 408 , 429 , 500 , 502 , 503 , 504 ],
};
const client = createClient ({
baseUrl: 'https://api.example.com' ,
retry: retryConfig ,
});
Comparison with Fetch Client
Feature Ky Client Fetch Client Dependencies Requires Ky Zero dependencies Browser Support Modern browsers Modern browsers Retry Support Built-in Manual Timeout Support Built-in Manual Request Hooks Ky hooks Interceptors only Response Hooks Ky hooks Interceptors only Bundle Size ~5KB ~2KB
Next Steps
Fetch Client Zero-dependency alternative
ofetch Client Universal fetch wrapper
Retry Configuration Configure automatic retries
Authentication Set up API authentication