Skip to content

Commit

Permalink
Support proxying for native fetch requests (#52)
Browse files Browse the repository at this point in the history
This change patches `undici` which is what `globalThis.fetch` uses in
modern Node versions (18+), allowing for native fetches to also be
routed through the proxy (`mockttp`) in Jambox!

Closes: #51
  • Loading branch information
hamlim authored Mar 8, 2024
1 parent cbadef8 commit cde31ed
Show file tree
Hide file tree
Showing 12 changed files with 260 additions and 3 deletions.
Binary file not shown.
Binary file not shown.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.2.0 - Add support for native `fetch` proxying

- feat: Support `globalThis.fetch` proxying, allowing native fetch requests to be cached/stubbed/etc

## 0.1.3 - Match paths containing dots, serialize browser config values

- fix: match pathnames with dot('.') literals in them
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "jambox",
"version": "0.1.3",
"version": "0.2.0",
"description": "Tool for recording and playing back HTTP requests.",
"bin": {
"jam": "./jam.mjs",
Expand Down Expand Up @@ -47,6 +47,7 @@
"svelte-routing": "^1.11.0",
"svelte-table": "^0.6.1",
"tail-file": "^1.4.15",
"undici": "6.7.0",
"wait-on": "^6.0.1",
"zen-observable": "^0.9.0"
},
Expand Down
Binary file not shown.
Binary file not shown.
Binary file modified recipes/nextjs-graphql-example/.yarn/install-state.gz
Binary file not shown.
10 changes: 9 additions & 1 deletion recipes/nextjs-graphql-example/pages/_app.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
export default function App({ Component, pageProps }) {
return <Component {...pageProps} />;
return (
<>
<nav>
<a href="/">Client Example</a>
<a href="/server-render">Server Rendered Example</a>
</nav>
<Component {...pageProps} />
</>
);
}
88 changes: 88 additions & 0 deletions recipes/nextjs-graphql-example/pages/server-render.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { useState } from 'react';

const query = `query Pokemon($name: String) {
pokemon(name: $name) {
name
image
}
}`;

export default function ServerRenderPage({data: initialData}) {
const [name, setName] = useState('Pikachu');
const [data, setData] = useState(initialData);
const [loading, setLoading] = useState(false);

const handleSearch = (e) => {
e.preventDefault();
setLoading(true);
fetch('https://graphql-pokemon2.vercel.app', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
},
body: JSON.stringify({
query,
variables: {
name,
},
}),
})
.then((res) => res.json())
.then(({ data }) => {
setLoading(false);
setData(data);
});
};

const handleInput = (e) => {
e.preventDefault();
setName(e.target.value);
};

return (
<>
<div>
<input value={name} onChange={handleInput}></input>
<button onClick={handleSearch}>Search</button>
</div>
<div>
{data ? (
<>
<h2>{data.pokemon.name}</h2>
<img src={data.pokemon.image} alt={data.pokemon.name} />
</>
) : loading ? (
<p>Loading…</p>
) : (
<p>Search for an image</p>
)}
</div>
</>
);
}


export async function getServerSideProps() {
const res = await fetch('https://graphql-pokemon2.vercel.app', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
},
body: JSON.stringify({
query,
variables: {
name: 'Pikachu',
},
}),
});

const { data } = await res.json();
console.log(data)
return {
props: {
data,
},
};
}
131 changes: 130 additions & 1 deletion src/__mocks__/cache-dir/16068043c24805b3a5ab193fa4a23b8c.json
Original file line number Diff line number Diff line change
@@ -1 +1,130 @@
{"request":{"id":"ebf337e5-ccdf-46be-b629-4651fefa8ad7","matchedRuleId":"2963a70a-837b-4563-bc96-e9049673f097","protocol":"https","httpVersion":"1.1","method":"POST","url":"https://graphql-pokemon2.vercel.app/","path":"/","remoteIpAddress":"::1","remotePort":50448,"headers":{"host":"graphql-pokemon2.vercel.app","connection":"keep-alive","content-length":"125","sec-ch-ua":"\"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"108\"","accept":"application/json","content-type":"application/json","sec-ch-ua-mobile":"?0","user-agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36","sec-ch-ua-platform":"\"Linux\"","origin":"https://jambox-demo-graphql.vercel.app","sec-fetch-site":"cross-site","sec-fetch-mode":"cors","sec-fetch-dest":"empty","referer":"https://jambox-demo-graphql.vercel.app/","accept-encoding":"gzip, deflate, br","accept-language":"en-US,en;q=0.9"},"rawHeaders":[["Host","graphql-pokemon2.vercel.app"],["Connection","keep-alive"],["Content-Length","125"],["sec-ch-ua","\"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"108\""],["Accept","application/json"],["Content-Type","application/json"],["sec-ch-ua-mobile","?0"],["User-Agent","Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"],["sec-ch-ua-platform","\"Linux\""],["Origin","https://jambox-demo-graphql.vercel.app"],["Sec-Fetch-Site","cross-site"],["Sec-Fetch-Mode","cors"],["Sec-Fetch-Dest","empty"],["Referer","https://jambox-demo-graphql.vercel.app/"],["Accept-Encoding","gzip, deflate, br"],["Accept-Language","en-US,en;q=0.9"]],"tags":[],"timingEvents":{"startTime":1673212233255,"startTimestamp":2040117.9996999986,"bodyReceivedTimestamp":2040118.9439219981},"body":{"buffer":{"type":"Buffer","data":[123,34,113,117,101,114,121,34,58,34,113,117,101,114,121,32,80,111,107,101,109,111,110,40,36,110,97,109,101,58,32,83,116,114,105,110,103,41,32,123,92,110,32,112,111,107,101,109,111,110,40,110,97,109,101,58,32,36,110,97,109,101,41,32,123,92,110,32,32,32,110,97,109,101,92,110,32,32,32,105,109,97,103,101,92,110,32,125,92,110,125,34,44,34,118,97,114,105,97,98,108,101,115,34,58,123,34,110,97,109,101,34,58,34,83,108,111,119,112,111,107,101,34,125,125]}}},"response":{"id":"ebf337e5-ccdf-46be-b629-4651fefa8ad7","statusCode":200,"timingEvents":{"startTime":1673212233255,"startTimestamp":2040117.9996999986,"bodyReceivedTimestamp":2040118.9439219981,"headersSentTimestamp":2040368.6721789986,"responseSentTimestamp":2040372.3621459976},"tags":[],"statusMessage":"OK","headers":{"access-control-allow-methods":"GET,HEAD,PUT,POST,DELETE","access-control-allow-origin":"https://jambox-demo-graphql.vercel.app","cache-control":"public, max-age=0, must-revalidate","connection":"keep-alive","content-length":"97","content-type":"application/json; charset=utf-8","date":"Sun, 08 Jan 2023 21:10:33 GMT","server":"Vercel","strict-transport-security":"max-age=63072000; includeSubDomains; preload","x-vercel-cache":"MISS","x-vercel-id":"iad1::sfo1::qnkr7-1673212233783-e24fced79c98"},"rawHeaders":[["Access-Control-Allow-Methods","GET,HEAD,PUT,POST,DELETE"],["Access-Control-Allow-Origin","https://jambox-demo-graphql.vercel.app"],["Cache-Control","public, max-age=0, must-revalidate"],["Connection","keep-alive"],["Content-Length","97"],["Content-Type","application/json; charset=utf-8"],["Date","Sun, 08 Jan 2023 21:10:33 GMT"],["Server","Vercel"],["Strict-Transport-Security","max-age=63072000; includeSubDomains; preload"],["X-Vercel-Cache","MISS"],["X-Vercel-Id","iad1::sfo1::qnkr7-1673212233783-e24fced79c98"]],"body":{"buffer":{"type":"Buffer","data":[123,34,100,97,116,97,34,58,123,34,112,111,107,101,109,111,110,34,58,123,34,110,97,109,101,34,58,34,83,108,111,119,112,111,107,101,34,44,34,105,109,97,103,101,34,58,34,104,116,116,112,115,58,47,47,105,109,103,46,112,111,107,101,109,111,110,100,98,46,110,101,116,47,97,114,116,119,111,114,107,47,115,108,111,119,112,111,107,101,46,106,112,103,34,125,125,125]}}}}
{
"request": {
"id": "ebf337e5-ccdf-46be-b629-4651fefa8ad7",
"matchedRuleId": "2963a70a-837b-4563-bc96-e9049673f097",
"protocol": "https",
"httpVersion": "1.1",
"method": "POST",
"url": "https://graphql-pokemon2.vercel.app/",
"path": "/",
"remoteIpAddress": "::1",
"remotePort": 50448,
"headers": {
"host": "graphql-pokemon2.vercel.app",
"connection": "keep-alive",
"content-length": "125",
"sec-ch-ua": "\"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"108\"",
"accept": "application/json",
"content-type": "application/json",
"sec-ch-ua-mobile": "?0",
"user-agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36",
"sec-ch-ua-platform": "\"Linux\"",
"origin": "https://jambox-demo-graphql.vercel.app",
"sec-fetch-site": "cross-site",
"sec-fetch-mode": "cors",
"sec-fetch-dest": "empty",
"referer": "https://jambox-demo-graphql.vercel.app/",
"accept-encoding": "gzip, deflate, br",
"accept-language": "en-US,en;q=0.9"
},
"rawHeaders": [
["Host", "graphql-pokemon2.vercel.app"],
["Connection", "keep-alive"],
["Content-Length", "125"],
["sec-ch-ua", "\"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"108\""],
["Accept", "application/json"],
["Content-Type", "application/json"],
["sec-ch-ua-mobile", "?0"],
[
"User-Agent",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"
],
["sec-ch-ua-platform", "\"Linux\""],
["Origin", "https://jambox-demo-graphql.vercel.app"],
["Sec-Fetch-Site", "cross-site"],
["Sec-Fetch-Mode", "cors"],
["Sec-Fetch-Dest", "empty"],
["Referer", "https://jambox-demo-graphql.vercel.app/"],
["Accept-Encoding", "gzip, deflate, br"],
["Accept-Language", "en-US,en;q=0.9"]
],
"tags": [],
"timingEvents": {
"startTime": 1673212233255,
"startTimestamp": 2040117.9996999986,
"bodyReceivedTimestamp": 2040118.9439219981
},
"body": {
"buffer": {
"type": "Buffer",
"data": [
123, 34, 113, 117, 101, 114, 121, 34, 58, 34, 113, 117, 101, 114, 121,
32, 80, 111, 107, 101, 109, 111, 110, 40, 36, 110, 97, 109, 101, 58,
32, 83, 116, 114, 105, 110, 103, 41, 32, 123, 92, 110, 32, 112, 111,
107, 101, 109, 111, 110, 40, 110, 97, 109, 101, 58, 32, 36, 110, 97,
109, 101, 41, 32, 123, 92, 110, 32, 32, 32, 110, 97, 109, 101, 92,
110, 32, 32, 32, 105, 109, 97, 103, 101, 92, 110, 32, 125, 92, 110,
125, 34, 44, 34, 118, 97, 114, 105, 97, 98, 108, 101, 115, 34, 58,
123, 34, 110, 97, 109, 101, 34, 58, 34, 83, 108, 111, 119, 112, 111,
107, 101, 34, 125, 125
]
}
}
},
"response": {
"id": "ebf337e5-ccdf-46be-b629-4651fefa8ad7",
"statusCode": 200,
"timingEvents": {
"startTime": 1673212233255,
"startTimestamp": 2040117.9996999986,
"bodyReceivedTimestamp": 2040118.9439219981,
"headersSentTimestamp": 2040368.6721789986,
"responseSentTimestamp": 2040372.3621459976
},
"tags": [],
"statusMessage": "OK",
"headers": {
"access-control-allow-methods": "GET,HEAD,PUT,POST,DELETE",
"access-control-allow-origin": "https://jambox-demo-graphql.vercel.app",
"cache-control": "public, max-age=0, must-revalidate",
"connection": "keep-alive",
"content-length": "97",
"content-type": "application/json; charset=utf-8",
"date": "Sun, 08 Jan 2023 21:10:33 GMT",
"server": "Vercel",
"strict-transport-security": "max-age=63072000; includeSubDomains; preload",
"x-vercel-cache": "MISS",
"x-vercel-id": "iad1::sfo1::qnkr7-1673212233783-e24fced79c98"
},
"rawHeaders": [
["Access-Control-Allow-Methods", "GET,HEAD,PUT,POST,DELETE"],
["Access-Control-Allow-Origin", "https://jambox-demo-graphql.vercel.app"],
["Cache-Control", "public, max-age=0, must-revalidate"],
["Connection", "keep-alive"],
["Content-Length", "97"],
["Content-Type", "application/json; charset=utf-8"],
["Date", "Sun, 08 Jan 2023 21:10:33 GMT"],
["Server", "Vercel"],
[
"Strict-Transport-Security",
"max-age=63072000; includeSubDomains; preload"
],
["X-Vercel-Cache", "MISS"],
["X-Vercel-Id", "iad1::sfo1::qnkr7-1673212233783-e24fced79c98"]
],
"body": {
"buffer": {
"type": "Buffer",
"data": [
123, 34, 100, 97, 116, 97, 34, 58, 123, 34, 112, 111, 107, 101, 109,
111, 110, 34, 58, 123, 34, 110, 97, 109, 101, 34, 58, 34, 83, 108,
111, 119, 112, 111, 107, 101, 34, 44, 34, 105, 109, 97, 103, 101, 34,
58, 34, 104, 116, 116, 112, 115, 58, 47, 47, 105, 109, 103, 46, 112,
111, 107, 101, 109, 111, 110, 100, 98, 46, 110, 101, 116, 47, 97, 114,
116, 119, 111, 114, 107, 47, 115, 108, 111, 119, 112, 111, 107, 101,
46, 106, 112, 103, 34, 125, 125, 125
]
}
}
}
}
10 changes: 10 additions & 0 deletions src/script-helper.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,12 @@
const undici = require('undici');
const globalAgent = require('global-agent');

globalAgent.bootstrap();

// Configure "native" `fetch` (e.g. `globalThis.fetch` in Node.js)
// to work with the `global-agent` proxy
// @see: https://github.com/gajus/global-agent/issues/52#issuecomment-1134525621
const ProxyAgent = undici.ProxyAgent;
const setGlobalDispatcher = undici.setGlobalDispatcher;

setGlobalDispatcher(new ProxyAgent(process.env.GLOBAL_AGENT_HTTP_PROXY));
17 changes: 17 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1421,6 +1421,13 @@ __metadata:
languageName: node
linkType: hard

"@fastify/busboy@npm:^2.0.0":
version: 2.1.1
resolution: "@fastify/busboy@npm:2.1.1"
checksum: 42c32ef75e906c9a4809c1e1930a5ca6d4ddc8d138e1a8c8ba5ea07f997db32210617d23b2e4a85fe376316a41a1a0439fc6ff2dedf5126d96f45a9d80754fb2
languageName: node
linkType: hard

"@floating-ui/core@npm:^1.1.0, @floating-ui/core@npm:^1.3.1":
version: 1.3.1
resolution: "@floating-ui/core@npm:1.3.1"
Expand Down Expand Up @@ -6145,6 +6152,7 @@ __metadata:
svelte-watch-resize: ^1.0.3
tail-file: ^1.4.15
typescript: ^5.1.3
undici: 6.7.0
wait-on: ^6.0.1
webextension-polyfill: ^0.10.0
webpack: ^5.74.0
Expand Down Expand Up @@ -9745,6 +9753,15 @@ __metadata:
languageName: node
linkType: hard

"undici@npm:6.7.0":
version: 6.7.0
resolution: "undici@npm:6.7.0"
dependencies:
"@fastify/busboy": ^2.0.0
checksum: bc03abd66d2a5db49e46e80453cf32793933db4a56aea5cd5957614e15762a83ef8a00fc54058c8c5fa9c4f4777060b67f37cc98860f49f95f191075cf076d0b
languageName: node
linkType: hard

"unicode-canonical-property-names-ecmascript@npm:^2.0.0":
version: 2.0.0
resolution: "unicode-canonical-property-names-ecmascript@npm:2.0.0"
Expand Down

0 comments on commit cde31ed

Please sign in to comment.