0
# @smithy/fetch-http-handler
1
2
@smithy/fetch-http-handler is a TypeScript library that provides a fetch-based HTTP request handler specifically designed for browser applications as part of the Smithy TypeScript ecosystem. It implements the default `requestHandler` used in browser environments, leveraging the modern Fetch API to handle HTTP requests with support for request timeouts, streaming responses, and proper error handling.
3
4
## Package Information
5
6
- **Package Name**: @smithy/fetch-http-handler
7
- **Package Type**: npm
8
- **Language**: TypeScript
9
- **Installation**: `npm install @smithy/fetch-http-handler`
10
11
## Core Imports
12
13
```typescript
14
import { FetchHttpHandler, streamCollector } from "@smithy/fetch-http-handler";
15
import type { FetchHttpHandlerOptions } from "@smithy/fetch-http-handler";
16
```
17
18
For CommonJS:
19
20
```javascript
21
const { FetchHttpHandler, streamCollector } = require("@smithy/fetch-http-handler");
22
```
23
24
## Basic Usage
25
26
```typescript
27
import { FetchHttpHandler } from "@smithy/fetch-http-handler";
28
import { HttpRequest } from "@smithy/protocol-http";
29
30
// Create handler with options
31
const handler = new FetchHttpHandler({
32
requestTimeout: 5000,
33
keepAlive: true,
34
credentials: 'same-origin'
35
});
36
37
// Handle an HTTP request
38
const request = new HttpRequest({
39
method: "GET",
40
hostname: "api.example.com",
41
path: "/users",
42
headers: { "Accept": "application/json" }
43
});
44
45
const { response } = await handler.handle(request);
46
console.log(response.statusCode, response.headers);
47
48
// Use static create method
49
const handler2 = FetchHttpHandler.create({
50
requestTimeout: 10000
51
});
52
```
53
54
## Architecture
55
56
The package is built around several key components:
57
58
- **FetchHttpHandler Class**: Main HTTP handler implementing the Smithy HttpHandler interface
59
- **Stream Collection**: Utilities for collecting data from Blob and ReadableStream objects
60
- **Request Construction**: Internal utilities for creating fetch-compatible Request objects
61
- **Timeout Management**: Promise-based timeout handling for request lifecycle
62
- **Configuration Management**: Dynamic configuration updates and provider pattern support
63
64
## Capabilities
65
66
### HTTP Request Handling
67
68
Core HTTP request handling using the Fetch API with comprehensive configuration options and error handling.
69
70
```typescript { .api }
71
class FetchHttpHandler implements HttpHandler<FetchHttpHandlerOptions> {
72
constructor(options?: FetchHttpHandlerOptions | Provider<FetchHttpHandlerOptions | void>);
73
74
static create(
75
instanceOrOptions?: HttpHandler<any> | FetchHttpHandlerOptions | Provider<FetchHttpHandlerOptions | void>
76
): HttpHandler<any> | FetchHttpHandler;
77
78
handle(request: HttpRequest, options?: HttpHandlerOptions): Promise<{ response: HttpResponse }>;
79
80
destroy(): void;
81
82
updateHttpClientConfig(key: keyof FetchHttpHandlerOptions, value: FetchHttpHandlerOptions[typeof key]): void;
83
84
httpHandlerConfigs(): FetchHttpHandlerOptions;
85
}
86
```
87
88
**Usage Examples:**
89
90
```typescript
91
import { FetchHttpHandler } from "@smithy/fetch-http-handler";
92
import { HttpRequest } from "@smithy/protocol-http";
93
94
// Basic handler with timeout
95
const handler = new FetchHttpHandler({
96
requestTimeout: 5000
97
});
98
99
// Handle POST request with body
100
const postRequest = new HttpRequest({
101
method: "POST",
102
hostname: "api.example.com",
103
path: "/data",
104
headers: { "Content-Type": "application/json" },
105
body: JSON.stringify({ key: "value" })
106
});
107
108
const { response } = await handler.handle(postRequest);
109
110
// Handle request with abort signal
111
const controller = new AbortController();
112
const { response: abortableResponse } = await handler.handle(
113
postRequest,
114
{ abortSignal: controller.signal }
115
);
116
117
// Update configuration dynamically
118
handler.updateHttpClientConfig("requestTimeout", 10000);
119
```
120
121
### Stream Collection
122
123
Utilities for collecting data from Blob or ReadableStream objects into Uint8Array format.
124
125
```typescript { .api }
126
/**
127
* Collects data from a Blob or ReadableStream into a Uint8Array
128
* @param stream - Blob or ReadableStream to collect data from
129
* @returns Promise resolving to collected data as Uint8Array
130
*/
131
const streamCollector: StreamCollector = (stream: Blob | ReadableStream): Promise<Uint8Array>;
132
133
type StreamCollector = (stream: Blob | ReadableStream) => Promise<Uint8Array>;
134
```
135
136
**Usage Examples:**
137
138
```typescript
139
import { streamCollector } from "@smithy/fetch-http-handler";
140
141
// Collect from ReadableStream
142
const response = await fetch('/api/data');
143
if (response.body) {
144
const data = await streamCollector(response.body);
145
console.log('Collected bytes:', data.length);
146
}
147
148
// Collect from Blob
149
const blob = new Blob(['Hello, world!']);
150
const uint8Array = await streamCollector(blob);
151
console.log('Blob as bytes:', uint8Array);
152
```
153
154
### Configuration Options
155
156
Comprehensive configuration interface for customizing HTTP request behavior.
157
158
```typescript { .api }
159
interface FetchHttpHandlerOptions {
160
/**
161
* The number of milliseconds a request can take before being automatically
162
* terminated.
163
*/
164
requestTimeout?: number;
165
166
/**
167
* Whether to allow the request to outlive the page. Default value is false.
168
*
169
* There may be limitations to the payload size, number of concurrent requests,
170
* request duration etc. when using keepalive in browsers.
171
*
172
* These may change over time, so look for up to date information about
173
* these limitations before enabling keepalive.
174
*/
175
keepAlive?: boolean;
176
177
/**
178
* A string indicating whether credentials will be sent with the request always, never, or
179
* only when sent to a same-origin URL.
180
* @see https://developer.mozilla.org/en-US/docs/Web/API/Request/credentials
181
*/
182
credentials?: "include" | "omit" | "same-origin" | undefined | string;
183
184
/**
185
* Cache settings for fetch.
186
* @see https://developer.mozilla.org/en-US/docs/Web/API/Request/cache
187
*/
188
cache?: "default" | "force-cache" | "no-cache" | "no-store" | "only-if-cached" | "reload";
189
190
/**
191
* An optional function that produces additional RequestInit
192
* parameters for each httpRequest.
193
*
194
* This is applied last via merging with Object.assign() and overwrites other values
195
* set from other sources.
196
*
197
* @example
198
* ```js
199
* new Client({
200
* requestHandler: {
201
* requestInit(httpRequest) {
202
* return { cache: "no-store" };
203
* }
204
* }
205
* });
206
* ```
207
*/
208
requestInit?: (httpRequest: HttpRequest) => RequestInit;
209
}
210
211
interface HttpHandlerOptions {
212
/** AbortSignal to cancel the request */
213
abortSignal?: AbortSignal;
214
}
215
216
type Provider<T> = () => Promise<T>;
217
```
218
219
### Internal Utilities
220
221
Internal utilities used by the FetchHttpHandler for request creation and timeout management.
222
223
```typescript { .api }
224
/**
225
* Creates a Request object for mocking/interception support
226
* @param url - Target URL for the request
227
* @param requestOptions - Optional RequestInit options
228
* @returns New Request object
229
*/
230
function createRequest(
231
url: string,
232
requestOptions?: RequestInit & AdditionalRequestParameters
233
): Request;
234
235
/**
236
* Creates a timeout promise that rejects after specified milliseconds
237
* @param timeoutInMs - Timeout duration in milliseconds (0 disables timeout)
238
* @returns Promise that rejects with TimeoutError
239
*/
240
function requestTimeout(timeoutInMs?: number): Promise<never>;
241
242
type AdditionalRequestParameters = {
243
/** Required in Node.js when Request has a body */
244
duplex?: "half";
245
};
246
247
const keepAliveSupport: {
248
supported: undefined | boolean;
249
};
250
```
251
252
## Types
253
254
### Core Types
255
256
```typescript { .api }
257
interface HttpRequest {
258
method: string;
259
protocol: string;
260
hostname: string;
261
port?: number;
262
path: string;
263
query?: Record<string, string>;
264
fragment?: string;
265
headers: HeaderBag;
266
username?: string;
267
password?: string;
268
body?: any;
269
}
270
271
interface HttpResponse {
272
statusCode: number;
273
reason?: string;
274
headers: HeaderBag;
275
body: any;
276
}
277
278
type HeaderBag = Record<string, string>;
279
280
interface HttpHandler<T> {
281
handle(request: HttpRequest, options?: HttpHandlerOptions): Promise<{ response: HttpResponse }>;
282
}
283
```
284
285
## Error Handling
286
287
The library handles several types of errors:
288
289
- **AbortError**: Thrown when a request is aborted via AbortSignal
290
- **TimeoutError**: Thrown when a request exceeds the specified timeout
291
- **Standard Fetch Errors**: Network errors, HTTP errors, and other fetch-related errors are propagated as-is
292
293
```typescript
294
try {
295
const { response } = await handler.handle(request);
296
} catch (error) {
297
if (error.name === 'AbortError') {
298
console.log('Request was aborted');
299
} else if (error.name === 'TimeoutError') {
300
console.log('Request timed out');
301
} else {
302
console.log('Other error:', error.message);
303
}
304
}
305
```
306
307
## Browser Compatibility
308
309
- **Primary Target**: Modern browsers with Fetch API support
310
- **Node.js Compatibility**: Requires Node.js 16.5.0+ with Web Streams API support
311
- **Features**: Automatic keepalive detection, AbortController support, streaming response handling
312
- **Recommendations**: Use @smithy/node-http-handler for dedicated Node.js applications