Skip to content

Commit ad3346c

Browse files
committed
Add client option to pass custom RequestInit object into fetch requests for supported implementations - refactor test to use own server/endpoint
1 parent 1c813c2 commit ad3346c

File tree

4 files changed

+460
-12
lines changed

4 files changed

+460
-12
lines changed

packages/openapi-fetch/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,9 @@
7474
"del-cli": "^5.1.0",
7575
"esbuild": "^0.23.1",
7676
"execa": "^8.0.1",
77+
"express": "^4.21.1",
7778
"feature-fetch": "^0.0.15",
79+
"node-forge": "^1.3.1",
7880
"openapi-typescript": "workspace:^",
7981
"openapi-typescript-codegen": "^0.25.0",
8082
"openapi-typescript-fetch": "^2.0.0",
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import express from "express";
2+
import { expect, test } from "vitest";
3+
import * as https from "node:https";
4+
import { Agent } from "undici";
5+
import createClient from "../../src/index.js";
6+
import * as forge from "node-forge";
7+
import * as crypto from "crypto";
8+
import httpServer from "express/lib/application.js";
9+
10+
const pki = forge.pki;
11+
12+
const genCACert = async (options = {}) => {
13+
options = {
14+
...{
15+
commonName: "Testing CA - DO NOT TRUST",
16+
bits: 2048,
17+
},
18+
...options,
19+
};
20+
21+
let keyPair = await new Promise((res, rej) => {
22+
pki.rsa.generateKeyPair({ bits: options.bits }, (error, pair) => {
23+
if (error) rej(error);
24+
else res(pair);
25+
});
26+
});
27+
28+
let cert = pki.createCertificate();
29+
cert.publicKey = keyPair.publicKey;
30+
cert.serialNumber = crypto.randomUUID().replace(/-/g, "");
31+
32+
cert.validity.notBefore = new Date();
33+
cert.validity.notBefore.setDate(cert.validity.notBefore.getDate() - 1);
34+
cert.validity.notAfter = new Date();
35+
cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 1);
36+
37+
cert.setSubject([{ name: "commonName", value: options.commonName }]);
38+
cert.setExtensions([{ name: "basicConstraints", cA: true }]);
39+
40+
cert.setIssuer(cert.subject.attributes);
41+
cert.sign(keyPair.privateKey, forge.md.sha256.create());
42+
43+
return {
44+
ca: {
45+
key: pki.privateKeyToPem(keyPair.privateKey),
46+
cert: pki.certificateToPem(cert),
47+
},
48+
fingerprint: forge.util.encode64(
49+
pki.getPublicKeyFingerprint(keyPair.publicKey, {
50+
type: "SubjectPublicKeyInfo",
51+
md: forge.md.sha256.create(),
52+
encoding: "binary",
53+
}),
54+
),
55+
};
56+
};
57+
58+
const caToBuffer = (ca) => {
59+
return {
60+
key: Buffer.from(ca.key),
61+
cert: Buffer.from(ca.cert),
62+
};
63+
};
64+
65+
const API_PORT = process.env.API_PORT || 4578;
66+
67+
const app = express();
68+
app.get("/v1/foo", (req, res) => {
69+
res.send("bar");
70+
});
71+
72+
test("requestInitExt", async () => {
73+
let cert = await genCACert();
74+
let buffers = caToBuffer(cert.ca);
75+
let options = {};
76+
options.key = buffers.key;
77+
options.cert = buffers.cert;
78+
const httpsServer = https.createServer(options, app);
79+
httpsServer.listen(4578);
80+
const dispatcher = new Agent({
81+
connect: {
82+
rejectUnauthorized: false,
83+
},
84+
});
85+
const client = createClient({ baseUrl: `https://localhost:${API_PORT}`, requestInitExt: { dispatcher } });
86+
const fetchResponse = await client.GET("/v1/foo", { parseAs: "text" });
87+
httpsServer.closeAllConnections();
88+
httpsServer.close();
89+
expect(fetchResponse.response.ok).toBe(true);
90+
});

packages/openapi-fetch/test/common/create-client.test.ts

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -39,18 +39,6 @@ describe("createClient options", () => {
3939
expect(actualURL.href).toBe("https://api.foo.bar/v3/resources");
4040
});
4141

42-
test("requestInitExt", async () => {
43-
const dispatcher = new Agent({
44-
connect: {
45-
rejectUnauthorized: false,
46-
},
47-
});
48-
const client = createClient({ requestInitExt: { dispatcher } });
49-
// @ts-ignore
50-
const fetchResponse = await client.GET("https://self-signed.badssl.com/", { parseAs: "text" });
51-
expect(fetchResponse.response.ok).toBe(true);
52-
});
53-
5442
describe("content-type", () => {
5543
const BODY_ACCEPTING_METHODS = [["PUT"], ["POST"], ["DELETE"], ["OPTIONS"], ["PATCH"]] as const;
5644
const ALL_METHODS = [...BODY_ACCEPTING_METHODS, ["GET"], ["HEAD"]] as const;

0 commit comments

Comments
 (0)