0
# Configuration Options
1
2
Comprehensive options for customizing request behavior including JSON handling, URL manipulation, timeouts, progress tracking, and fetch customization.
3
4
## Capabilities
5
6
### JSON Options
7
8
Configure how JSON data is handled in requests and responses.
9
10
```typescript { .api }
11
interface JsonOptions {
12
/** Shortcut for sending JSON data in request body */
13
json?: unknown;
14
/** Custom JSON parsing function for responses */
15
parseJson?: (text: string) => unknown;
16
/** Custom JSON stringification function for requests */
17
stringifyJson?: (data: unknown) => string;
18
}
19
```
20
21
**Usage Examples:**
22
23
```typescript
24
import ky from "ky";
25
26
// Send JSON data
27
const user = await ky.post("https://api.example.com/users", {
28
json: { name: "Alice", email: "alice@example.com", age: 30 }
29
}).json();
30
31
// Custom JSON parsing with date handling
32
const client = ky.create({
33
parseJson: (text) => {
34
return JSON.parse(text, (key, value) => {
35
if (key.endsWith("_at") || key.endsWith("Date")) {
36
return new Date(value);
37
}
38
return value;
39
});
40
}
41
});
42
43
// Custom JSON stringification with BigInt support
44
const bigIntClient = ky.create({
45
stringifyJson: (data) => {
46
return JSON.stringify(data, (key, value) => {
47
if (typeof value === "bigint") {
48
return value.toString();
49
}
50
return value;
51
});
52
}
53
});
54
55
// Safe JSON parsing with error handling
56
const safeClient = ky.create({
57
parseJson: (text) => {
58
try {
59
return JSON.parse(text);
60
} catch (error) {
61
console.error("JSON parse error:", error);
62
return { error: "Invalid JSON response" };
63
}
64
}
65
});
66
```
67
68
### URL and Search Parameters
69
70
Configure URL prefixes and search parameters for requests.
71
72
```typescript { .api }
73
interface UrlOptions {
74
/** URL prefix to prepend to requests */
75
prefixUrl?: URL | string;
76
/** Search parameters to include in request URL */
77
searchParams?: SearchParamsOption;
78
}
79
80
type SearchParamsInit = string | string[][] | Record<string, string> | URLSearchParams | undefined;
81
82
type SearchParamsOption =
83
| SearchParamsInit
84
| Record<string, string | number | boolean | undefined>
85
| Array<Array<string | number | boolean>>;
86
```
87
88
**Usage Examples:**
89
90
```typescript
91
import ky from "ky";
92
93
// API client with base URL
94
const apiClient = ky.create({
95
prefixUrl: "https://api.example.com/v1"
96
});
97
98
// All requests use the prefix
99
const users = await apiClient.get("users").json(); // GET https://api.example.com/v1/users
100
const user = await apiClient.get("users/123").json(); // GET https://api.example.com/v1/users/123
101
102
// Search parameters as object
103
const filteredData = await ky.get("https://api.example.com/data", {
104
searchParams: {
105
category: "electronics",
106
minPrice: 100,
107
maxPrice: 500,
108
inStock: true,
109
tags: undefined // Will be filtered out
110
}
111
}).json();
112
113
// Search parameters as URLSearchParams
114
const params = new URLSearchParams();
115
params.append("sort", "name");
116
params.append("sort", "date");
117
params.append("limit", "20");
118
119
const sortedData = await ky.get("https://api.example.com/items", {
120
searchParams: params
121
}).json();
122
123
// Search parameters as array
124
const complexParams = await ky.get("https://api.example.com/search", {
125
searchParams: [
126
["query", "javascript"],
127
["category", "programming"],
128
["category", "web"],
129
["format", "json"]
130
]
131
}).json();
132
```
133
134
### Timeout Configuration
135
136
Configure request timeouts to prevent hanging requests.
137
138
```typescript { .api }
139
interface TimeoutOptions {
140
/** Timeout in milliseconds, or false to disable */
141
timeout?: number | false;
142
}
143
```
144
145
**Usage Examples:**
146
147
```typescript
148
import ky from "ky";
149
150
// Global timeout for all requests
151
const fastClient = ky.create({
152
timeout: 5000 // 5 seconds
153
});
154
155
// Per-request timeout
156
const quickData = await ky.get("https://api.example.com/quick", {
157
timeout: 2000 // 2 seconds
158
}).json();
159
160
// Long timeout for slow operations
161
const largeFile = await ky.get("https://api.example.com/export", {
162
timeout: 60000 // 60 seconds
163
}).arrayBuffer();
164
165
// Disable timeout for streaming operations
166
const stream = await ky.get("https://api.example.com/stream", {
167
timeout: false
168
});
169
170
// Environment-specific timeouts
171
const timeoutClient = ky.create({
172
timeout: process.env.NODE_ENV === "development" ? 30000 : 10000
173
});
174
```
175
176
### Error Handling Configuration
177
178
Configure how HTTP errors are handled.
179
180
```typescript { .api }
181
interface ErrorOptions {
182
/** Whether to throw HTTPError for non-2xx status codes */
183
throwHttpErrors?: boolean;
184
}
185
```
186
187
**Usage Examples:**
188
189
```typescript
190
import ky from "ky";
191
192
// Disable automatic error throwing
193
const response = await ky.get("https://api.example.com/might-fail", {
194
throwHttpErrors: false
195
});
196
197
if (response.ok) {
198
const data = await response.json();
199
console.log("Success:", data);
200
} else {
201
console.log("Failed with status:", response.status);
202
}
203
204
// Client that never throws HTTP errors
205
const tolerantClient = ky.create({
206
throwHttpErrors: false
207
});
208
209
// Handle errors manually
210
const result = await tolerantClient.get("https://api.example.com/data");
211
if (result.status === 404) {
212
console.log("Resource not found");
213
} else if (result.status >= 500) {
214
console.log("Server error");
215
} else if (result.ok) {
216
const data = await result.json();
217
console.log("Data:", data);
218
}
219
```
220
221
### Progress Tracking
222
223
Track upload and download progress for large requests.
224
225
```typescript { .api }
226
interface ProgressOptions {
227
/** Download progress handler */
228
onDownloadProgress?: (progress: Progress, chunk: Uint8Array) => void;
229
/** Upload progress handler */
230
onUploadProgress?: (progress: Progress, chunk: Uint8Array) => void;
231
}
232
233
interface Progress {
234
/** Progress as decimal (0.0 to 1.0) */
235
percent: number;
236
/** Bytes transferred so far */
237
transferredBytes: number;
238
/** Total bytes (0 if unknown) */
239
totalBytes: number;
240
}
241
```
242
243
**Usage Examples:**
244
245
```typescript
246
import ky from "ky";
247
248
// Download progress tracking
249
const fileData = await ky.get("https://api.example.com/large-file.zip", {
250
onDownloadProgress: (progress, chunk) => {
251
const percentage = Math.round(progress.percent * 100);
252
console.log(`Download: ${percentage}% (${progress.transferredBytes}/${progress.totalBytes} bytes)`);
253
254
// Update progress bar
255
updateProgressBar(percentage);
256
}
257
}).arrayBuffer();
258
259
// Upload progress tracking
260
const formData = new FormData();
261
formData.append("file", largeFile);
262
263
const uploadResult = await ky.post("https://api.example.com/upload", {
264
body: formData,
265
onUploadProgress: (progress, chunk) => {
266
const percentage = Math.round(progress.percent * 100);
267
console.log(`Upload: ${percentage}% (${progress.transferredBytes}/${progress.totalBytes} bytes)`);
268
269
// Show upload status
270
setUploadStatus(`Uploading... ${percentage}%`);
271
}
272
}).json();
273
274
// Combined progress tracking
275
const processLargeFile = async () => {
276
const result = await ky.post("https://api.example.com/process", {
277
json: { fileUrl: "https://example.com/input.dat" },
278
onUploadProgress: (progress) => {
279
console.log(`Sending request: ${Math.round(progress.percent * 100)}%`);
280
},
281
onDownloadProgress: (progress) => {
282
console.log(`Receiving response: ${Math.round(progress.percent * 100)}%`);
283
}
284
}).json();
285
286
return result;
287
};
288
```
289
290
### Custom Fetch Implementation
291
292
Provide a custom fetch implementation for advanced use cases.
293
294
```typescript { .api }
295
interface FetchOptions {
296
/** Custom fetch implementation */
297
fetch?: (input: Input, init?: RequestInit) => Promise<Response>;
298
}
299
```
300
301
**Usage Examples:**
302
303
```typescript
304
import ky from "ky";
305
306
// Use custom fetch with additional features
307
const customClient = ky.create({
308
fetch: async (input, init) => {
309
// Add request logging
310
console.log(`Fetching: ${init?.method || "GET"} ${input}`);
311
312
// Use native fetch with modifications
313
const response = await fetch(input, {
314
...init,
315
// Add custom headers
316
headers: {
317
...init?.headers,
318
"X-Custom-Client": "ky-enhanced"
319
}
320
});
321
322
// Add response logging
323
console.log(`Response: ${response.status} ${input}`);
324
325
return response;
326
}
327
});
328
329
// Node.js with undici or node-fetch
330
import { fetch } from "undici";
331
332
const nodeClient = ky.create({
333
fetch: fetch as any
334
});
335
336
// Mock fetch for testing
337
const mockClient = ky.create({
338
fetch: async (input, init) => {
339
const url = input.toString();
340
341
if (url.includes("/users")) {
342
return new Response(JSON.stringify([
343
{ id: 1, name: "Alice" },
344
{ id: 2, name: "Bob" }
345
]), {
346
status: 200,
347
headers: { "Content-Type": "application/json" }
348
});
349
}
350
351
return new Response("Not found", { status: 404 });
352
}
353
});
354
```
355
356
## Complete Options Interface
357
358
```typescript { .api }
359
interface Options extends KyOptions, RequestInit {
360
method?: LiteralUnion<HttpMethod, string>;
361
headers?: KyHeadersInit;
362
}
363
364
interface KyOptions {
365
json?: unknown;
366
parseJson?: (text: string) => unknown;
367
stringifyJson?: (data: unknown) => string;
368
searchParams?: SearchParamsOption;
369
prefixUrl?: URL | string;
370
retry?: RetryOptions | number;
371
timeout?: number | false;
372
throwHttpErrors?: boolean;
373
onDownloadProgress?: (progress: Progress, chunk: Uint8Array) => void;
374
onUploadProgress?: (progress: Progress, chunk: Uint8Array) => void;
375
fetch?: (input: Input, init?: RequestInit) => Promise<Response>;
376
hooks?: Hooks;
377
}
378
379
type KyHeadersInit = NonNullable<RequestInit['headers']> | Record<string, string | undefined>;
380
381
type LiteralUnion<T extends U, U = string> = T | (U & Record<never, never>);
382
383
type HttpMethod = 'get' | 'post' | 'put' | 'patch' | 'head' | 'delete';
384
```