Skip to content

Commit cf9257e

Browse files
authored
feat(fetch-http-handler): add customization option for requestInit (#1397)
* feat(fetch-http-handler): add customization option for requestInit * comment wording
1 parent 918c402 commit cf9257e

File tree

4 files changed

+111
-0
lines changed

4 files changed

+111
-0
lines changed

.changeset/dull-tomatoes-wink.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@smithy/fetch-http-handler": patch
3+
"@smithy/types": patch
4+
---
5+
6+
add requestInit options to fetch

packages/fetch-http-handler/src/fetch-http-handler.spec.ts

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ let timeoutSpy: jest.SpyInstance<any>;
99

1010
(global as any).Request = mockRequest;
1111
(global as any).Headers = jest.fn();
12+
const globalFetch = global.fetch;
1213

1314
describe(FetchHttpHandler.name, () => {
1415
beforeEach(() => {
@@ -23,6 +24,10 @@ describe(FetchHttpHandler.name, () => {
2324
}
2425
});
2526

27+
afterAll(() => {
28+
global.fetch = globalFetch;
29+
});
30+
2631
it("makes requests using fetch", async () => {
2732
const mockResponse = {
2833
headers: {
@@ -454,6 +459,73 @@ describe(FetchHttpHandler.name, () => {
454459
});
455460
});
456461

462+
describe("custom requestInit", () => {
463+
it("should allow setting cache requestInit", async () => {
464+
const mockResponse = {
465+
headers: {
466+
entries() {
467+
return [];
468+
},
469+
},
470+
blob: jest.fn().mockResolvedValue(new Blob()),
471+
};
472+
const mockFetch = jest.fn().mockResolvedValue(mockResponse);
473+
(global as any).fetch = mockFetch;
474+
475+
const fetchHttpHandler = new FetchHttpHandler({
476+
cache: "no-store",
477+
});
478+
479+
await fetchHttpHandler.handle({} as any, {});
480+
481+
expect(mockRequest.mock.calls[0][1].cache).toBe("no-store");
482+
});
483+
484+
it("should allow setting custom requestInit", async () => {
485+
const mockResponse = {
486+
headers: {
487+
entries() {
488+
return [];
489+
},
490+
},
491+
blob: jest.fn().mockResolvedValue(new Blob()),
492+
};
493+
const mockFetch = jest.fn().mockResolvedValue(mockResponse);
494+
(global as any).fetch = mockFetch;
495+
496+
const fetchHttpHandler = new FetchHttpHandler({
497+
requestInit(req) {
498+
return {
499+
referrer: "me",
500+
cache: "reload",
501+
headers: {
502+
a: "a",
503+
b: req.headers.b,
504+
},
505+
};
506+
},
507+
});
508+
509+
await fetchHttpHandler.handle(
510+
{
511+
headers: {
512+
b: "b",
513+
},
514+
} as any,
515+
{}
516+
);
517+
518+
expect(mockRequest.mock.calls[0][1]).toEqual({
519+
referrer: "me",
520+
cache: "reload",
521+
headers: {
522+
a: "a",
523+
b: "b",
524+
},
525+
});
526+
});
527+
});
528+
457529
// The Blob implementation does not implement Blob.text, so we deal with it here.
458530
async function blobToText(blob: Blob): Promise<string> {
459531
const reader = new FileReader();

packages/fetch-http-handler/src/fetch-http-handler.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,9 @@ export class FetchHttpHandler implements HttpHandler<FetchHttpHandlerConfig> {
112112
headers: new Headers(request.headers),
113113
method: method,
114114
credentials,
115+
cache: this.config!.cache ?? "default",
115116
};
117+
116118
if (body) {
117119
requestOptions.duplex = "half";
118120
}
@@ -127,6 +129,10 @@ export class FetchHttpHandler implements HttpHandler<FetchHttpHandlerConfig> {
127129
requestOptions.keepalive = keepAlive;
128130
}
129131

132+
if (typeof this.config.requestInit === "function") {
133+
Object.assign(requestOptions, this.config.requestInit(request));
134+
}
135+
130136
let removeSignalEventListener = () => {};
131137

132138
const fetchRequest = new Request(url, requestOptions);

packages/types/src/http/httpHandlerInitialization.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { Agent as hAgent, AgentOptions as hAgentOptions } from "http";
22
import type { Agent as hsAgent, AgentOptions as hsAgentOptions } from "https";
33

4+
import { HttpRequest as IHttpRequest } from "../http";
45
import { Logger } from "../logger";
56

67
/**
@@ -97,4 +98,30 @@ export interface FetchHttpHandlerOptions {
9798
* @see https://developer.mozilla.org/en-US/docs/Web/API/Request/credentials
9899
*/
99100
credentials?: "include" | "omit" | "same-origin" | undefined | string;
101+
102+
/**
103+
* Cache settings for fetch.
104+
* @see https://developer.mozilla.org/en-US/docs/Web/API/Request/cache
105+
*/
106+
cache?: "default" | "force-cache" | "no-cache" | "no-store" | "only-if-cached" | "reload";
107+
108+
/**
109+
* An optional function that produces additional RequestInit
110+
* parameters for each httpRequest.
111+
*
112+
* This is applied last via merging with Object.assign() and overwrites other values
113+
* set from other sources.
114+
*
115+
* @example
116+
* ```js
117+
* new Client({
118+
* requestHandler: {
119+
* requestInit(httpRequest) {
120+
* return { cache: "no-store" };
121+
* }
122+
* }
123+
* });
124+
* ```
125+
*/
126+
requestInit?: (httpRequest: IHttpRequest) => RequestInit;
100127
}

0 commit comments

Comments
 (0)