A window.fetch polyfill for browsers that don't natively support the Fetch API
npx @tessl/cli install tessl/npm-whatwg-fetch@3.6.00
# whatwg-fetch
1
2
whatwg-fetch is a comprehensive polyfill implementation of the Fetch API for web browsers that don't natively support window.fetch. It provides a Promise-based mechanism for making HTTP requests as a modern replacement for XMLHttpRequest, following the WHATWG Fetch specification standards.
3
4
## Package Information
5
6
- **Package Name**: whatwg-fetch
7
- **Package Type**: npm
8
- **Language**: JavaScript
9
- **Installation**: `npm install whatwg-fetch`
10
11
## Core Imports
12
13
```javascript
14
import 'whatwg-fetch'
15
16
// Global polyfill - automatically installs window.fetch and related APIs
17
// Only installs when native fetch is not available
18
window.fetch(...)
19
```
20
21
For explicit access to polyfill components:
22
23
```javascript
24
import { fetch as fetchPolyfill, Headers, Request, Response, DOMException } from 'whatwg-fetch'
25
26
// Use polyfill explicitly alongside or instead of native
27
fetchPolyfill(...) // Always uses polyfill implementation
28
window.fetch(...) // Uses native browser version when available
29
```
30
31
CommonJS:
32
33
```javascript
34
require('whatwg-fetch');
35
36
// Global polyfill - automatically installs global.fetch, Headers, Request, Response
37
// Only installs when native fetch is not available
38
fetch(...)
39
```
40
41
## Basic Usage
42
43
```javascript
44
import 'whatwg-fetch'
45
46
// Simple GET request
47
fetch('/api/users')
48
.then(response => response.json())
49
.then(data => console.log(data))
50
.catch(error => console.error('Request failed:', error));
51
52
// POST with JSON data
53
fetch('/api/users', {
54
method: 'POST',
55
headers: {
56
'Content-Type': 'application/json'
57
},
58
body: JSON.stringify({
59
name: 'John Doe',
60
email: 'john@example.com'
61
})
62
})
63
.then(response => response.json())
64
.then(data => console.log('User created:', data));
65
66
// File upload with FormData
67
const formData = new FormData();
68
formData.append('file', fileInput.files[0]);
69
formData.append('description', 'Profile photo');
70
71
fetch('/upload', {
72
method: 'POST',
73
body: formData
74
})
75
.then(response => response.json());
76
```
77
78
## Architecture
79
80
whatwg-fetch implements the complete Fetch API specification with these core components:
81
82
- **Fetch Function**: Main entry point for HTTP requests with Promise-based interface
83
- **Request Class**: HTTP request representation with full configuration support
84
- **Response Class**: HTTP response representation with body parsing methods
85
- **Headers Class**: HTTP headers management with case-insensitive operations
86
- **Body Interface**: Shared body reading methods for Request and Response
87
- **Global Polyfill**: Automatic installation when native fetch is unavailable
88
89
## Capabilities
90
91
### HTTP Requests
92
93
Core fetch functionality for making HTTP requests with full Promise support.
94
95
```javascript { .api }
96
/**
97
* Make an HTTP request
98
* @param input - URL string, URL object, or Request object
99
* @param init - Optional request configuration
100
* @returns Promise that resolves to Response object
101
*/
102
function fetch(input: RequestInfo, init?: RequestInit): Promise<Response>;
103
104
// Polyfill identification property
105
fetch.polyfill: boolean;
106
107
type RequestInfo = Request | string;
108
109
interface RequestInit {
110
method?: string;
111
headers?: HeadersInit;
112
body?: BodyInit;
113
credentials?: 'omit' | 'same-origin' | 'include';
114
mode?: string;
115
referrer?: string;
116
signal?: AbortSignal;
117
}
118
119
type ModeType = string;
120
121
type BodyInit = string | URLSearchParams | FormData | Blob | ArrayBuffer | ArrayBufferView | null;
122
type HeadersInit = Headers | Record<string, string> | [string, string][];
123
```
124
125
**Usage Examples:**
126
127
```javascript
128
// GET request
129
fetch('/api/data')
130
.then(response => {
131
if (!response.ok) {
132
throw new Error(`HTTP error! status: ${response.status}`);
133
}
134
return response.json();
135
});
136
137
// POST request with credentials
138
fetch('/api/login', {
139
method: 'POST',
140
credentials: 'include',
141
headers: {
142
'Content-Type': 'application/json'
143
},
144
body: JSON.stringify({ username, password })
145
});
146
147
// Request with abort signal
148
const controller = new AbortController();
149
fetch('/api/data', {
150
signal: controller.signal
151
});
152
153
// Cancel the request
154
controller.abort();
155
```
156
157
### Request Construction
158
159
Create and configure HTTP requests with full type safety and validation.
160
161
```javascript { .api }
162
/**
163
* Create a new Request object
164
* @param input - URL string, URL object, or existing Request
165
* @param options - Request configuration options
166
*/
167
class Request {
168
constructor(input: RequestInfo, options?: RequestInit);
169
170
// Properties
171
readonly url: string;
172
readonly method: string;
173
readonly headers: Headers;
174
readonly credentials: 'omit' | 'same-origin' | 'include';
175
readonly mode: ModeType;
176
readonly signal: AbortSignal;
177
readonly referrer: string;
178
readonly bodyUsed: boolean;
179
180
// Methods
181
clone(): Request;
182
arrayBuffer(): Promise<ArrayBuffer>;
183
blob(): Promise<Blob>;
184
formData(): Promise<FormData>;
185
json(): Promise<any>;
186
text(): Promise<string>;
187
}
188
```
189
190
**Usage Examples:**
191
192
```javascript
193
// Create request with configuration
194
const request = new Request('/api/users', {
195
method: 'POST',
196
headers: {
197
'Content-Type': 'application/json',
198
'Authorization': 'Bearer token123'
199
},
200
body: JSON.stringify({ name: 'Alice' })
201
});
202
203
// Clone request for retry logic
204
const originalRequest = new Request('/api/data', { method: 'GET' });
205
const retryRequest = originalRequest.clone();
206
207
// Read request body
208
const requestData = await request.json();
209
```
210
211
### Response Handling
212
213
Handle HTTP responses with comprehensive body parsing and metadata access.
214
215
```javascript { .api }
216
/**
217
* HTTP Response representation
218
* @param bodyInit - Response body content
219
* @param options - Response configuration
220
*/
221
class Response {
222
constructor(bodyInit?: BodyInit, options?: ResponseInit);
223
224
// Properties
225
readonly url: string;
226
readonly status: number;
227
readonly statusText: string;
228
readonly ok: boolean;
229
readonly headers: Headers;
230
readonly type: 'default' | 'error';
231
readonly bodyUsed: boolean;
232
233
// Methods
234
clone(): Response;
235
arrayBuffer(): Promise<ArrayBuffer>;
236
blob(): Promise<Blob>;
237
formData(): Promise<FormData>;
238
json(): Promise<any>;
239
text(): Promise<string>;
240
241
// Static methods
242
static error(): Response;
243
static redirect(url: string, status?: number): Response;
244
}
245
246
interface ResponseInit {
247
status?: number;
248
statusText?: string;
249
headers?: HeadersInit;
250
url?: string;
251
}
252
```
253
254
**Usage Examples:**
255
256
```javascript
257
// Handle response with status checking
258
fetch('/api/data')
259
.then(response => {
260
console.log(`Status: ${response.status} ${response.statusText}`);
261
console.log(`Content-Type: ${response.headers.get('Content-Type')}`);
262
263
if (response.ok) {
264
return response.json();
265
} else {
266
throw new Error(`Request failed: ${response.status}`);
267
}
268
});
269
270
// Create custom responses
271
const successResponse = new Response(
272
JSON.stringify({ message: 'Success' }),
273
{
274
status: 200,
275
statusText: 'OK',
276
headers: { 'Content-Type': 'application/json' }
277
}
278
);
279
280
const errorResponse = Response.error();
281
const redirectResponse = Response.redirect('/login', 302);
282
```
283
284
### Headers Management
285
286
Manage HTTP headers with case-insensitive operations and iteration support.
287
288
```javascript { .api }
289
/**
290
* HTTP headers collection
291
* @param init - Initial headers as object, array, or Headers instance
292
*/
293
class Headers {
294
constructor(init?: HeadersInit);
295
296
// Methods
297
append(name: string, value: string): void;
298
delete(name: string): void;
299
get(name: string): string | null;
300
has(name: string): boolean;
301
set(name: string, value: string): void;
302
forEach(callback: (value: string, name: string, headers: Headers) => void, thisArg?: any): void;
303
304
// Iterator methods
305
keys(): IterableIterator<string>;
306
values(): IterableIterator<string>;
307
entries(): IterableIterator<[string, string]>;
308
[Symbol.iterator](): IterableIterator<[string, string]>;
309
}
310
```
311
312
**Usage Examples:**
313
314
```javascript
315
// Create headers from object
316
const headers = new Headers({
317
'Content-Type': 'application/json',
318
'Authorization': 'Bearer token123'
319
});
320
321
// Add headers
322
headers.append('X-Custom-Header', 'value1');
323
headers.append('X-Custom-Header', 'value2'); // Combines: "value1, value2"
324
325
// Check and get headers
326
if (headers.has('Content-Type')) {
327
console.log(headers.get('Content-Type')); // "application/json"
328
}
329
330
// Iterate over headers
331
headers.forEach((value, name) => {
332
console.log(`${name}: ${value}`);
333
});
334
335
// Use with fetch
336
fetch('/api/data', {
337
headers: new Headers({
338
'Accept': 'application/json',
339
'X-API-Key': 'key123'
340
})
341
});
342
```
343
344
### Error Handling
345
346
Handle fetch errors and request abortion with standard exception types.
347
348
```javascript { .api }
349
/**
350
* DOM Exception for fetch errors
351
* @param message - Error message
352
* @param name - Exception name (e.g., 'AbortError')
353
*/
354
class DOMException extends Error {
355
constructor(message?: string, name?: string);
356
357
readonly name: string;
358
readonly message: string;
359
readonly stack: string;
360
}
361
```
362
363
**Usage Examples:**
364
365
```javascript
366
// Handle different error types
367
const controller = new AbortController();
368
369
fetch('/api/data', { signal: controller.signal })
370
.then(response => response.json())
371
.catch(error => {
372
if (error.name === 'AbortError') {
373
console.log('Request was aborted');
374
} else if (error instanceof TypeError) {
375
console.log('Network error or request failed');
376
} else {
377
console.log('Other error:', error.message);
378
}
379
});
380
381
// Abort after timeout
382
setTimeout(() => controller.abort(), 5000);
383
384
// Check if polyfill is active
385
if (fetch.polyfill) {
386
console.log('Using whatwg-fetch polyfill');
387
} else {
388
console.log('Using native fetch implementation');
389
}
390
391
// Custom error handling for HTTP errors
392
function checkStatus(response) {
393
if (response.status >= 200 && response.status < 300) {
394
return response;
395
} else {
396
const error = new Error(response.statusText);
397
error.response = response;
398
throw error;
399
}
400
}
401
402
fetch('/api/data')
403
.then(checkStatus)
404
.then(response => response.json());
405
```
406
407
## Browser Compatibility
408
409
- **Chrome**: All versions
410
- **Firefox**: All versions
411
- **Safari**: 6.1+
412
- **Internet Explorer**: 10+
413
- **Modern Browsers**: Use native fetch when available
414
415
The polyfill automatically detects native fetch support and only installs itself when needed.
416
417
## Important Notes
418
419
- **Promise Rejection**: fetch() only rejects on network errors, not HTTP error status codes (404, 500, etc.)
420
- **Credentials**: Use `credentials: 'same-origin'` for maximum compatibility with cookies
421
- **CORS**: Cross-origin requests require proper server-side CORS configuration
422
- **Node.js**: This polyfill is browser-only and does not work in Node.js environments
423
- **AbortController**: Requires separate polyfill for browsers without native AbortController support
424
- **Polyfill Detection**: Check `fetch.polyfill` property to determine if polyfill is active
425
- **Automatic Installation**: The polyfill automatically detects native support and only activates when needed
426
- **Global Scope**: Importing the module automatically installs fetch, Headers, Request, Response globally
427
- **No-Cache Headers**: GET/HEAD requests with `cache: 'no-store'` or `cache: 'no-cache'` get timestamp parameters added
428
- **File Protocol**: Local file:// URLs receive status 200 even when xhr.status is outside normal range