openapi-typescript icon indicating copy to clipboard operation
openapi-typescript copied to clipboard

Allow providing custom `Request` and `Response`

Open Dzieni opened this issue 1 year ago • 1 comments

Description

I am using openapi-fetch in Node.js. As you probably know, the built-in fetch is provided by Undici project, which is still in development. Usually it's better to install undici package separately and have a warranty that fetching works the same, no matter the runtime version. Also, if you want to use more sophisticated features (like mocking or proxy connection), they're not available in the built-in version.

When I tried to use Undici in your app, it broke down due to some inconsistency of Request object behavior (despite both implement the WHATWG spec). Here is a code snippet that shows the inconsistency.

// ran on Undici 6.6.2 and Node 20.11.1 (which bundles Undici 5.28.3)
// interesingly, the problem persists when I change the dependency version to 5.28.3
import { Request as UndiciRequest, fetch as undiciFetch } from "undici";

const req = new Request("http://example.com");
const undiciReq = new UndiciRequest("http://example.com");

await fetch(req.clone())
	.then((res) => {
		res.blob().catch(() => {});
		console.log("global Request + global fetch => works");
	})
	.catch((e) => {
		console.error("global Request + global fetch => broken", e);
	});

await undiciFetch(undiciReq.clone())
	.then((res) => {
		res.blob().catch(() => {});
		console.log("undici Request + undici fetch => works");
	})
	.catch((e) => {
		console.error("undici Request + undici fetch => broken", e);
	});

await undiciFetch(req.clone())
	.then((res) => {
		res.blob().catch(() => {});
		console.log("global Request + undici fetch => works");
	})
	.catch((e) => {
		console.error("global Request + undici fetch => broken", e);
	});

await fetch(undiciReq.clone())
	.then((res) => {
		res.blob().catch(() => {});
		console.log("undici Request + global fetch => works");
	})
	.catch((e) => {
		console.error("undici Request + global fetch => broken", e);
	});

Results with:

global Request + global fetch => works
undici Request + undici fetch => works
global Request + undici fetch => broken TypeError: Failed to parse URL from [object Request]
    at fetch (/Users/michal/undiciReqInconsistency/node_modules/undici/index.js:103:13)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async file:///Users/michal/undiciReqInconsistency/index.mjs:24:1 {
  [cause]: TypeError: Invalid URL
      at new URL (node:internal/url:775:36)
      at new Request (/Users/michal/undiciReqInconsistency/node_modules/undici/lib/fetch/request.js:85:21)
      at fetch (/Users/michal/undiciReqInconsistency/node_modules/undici/lib/fetch/index.js:138:21)
      at fetch (/Users/michal/undiciReqInconsistency/node_modules/undici/index.js:100:18)
      at file:///Users/michal/undiciReqInconsistency/index.mjs:24:7
      at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {
    code: 'ERR_INVALID_URL',
    input: '[object Request]'
  }
}
undici Request + global fetch => broken TypeError: Failed to parse URL from [object Request]
    at node:internal/deps/undici/undici:12345:11
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async file:///Users/michal/undiciReqInconsistency/index.mjs:33:1 {
  [cause]: TypeError: Invalid URL
      at new URL (node:internal/url:775:36)
      at new Request (node:internal/deps/undici/undici:5853:25)
      at fetch (node:internal/deps/undici/undici:10123:25)
      at Object.fetch (node:internal/deps/undici/undici:12344:10)
      at fetch (node:internal/process/pre_execution:336:27)
      at file:///Users/michal/undiciReqInconsistency/index.mjs:33:7
      at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {
    code: 'ERR_INVALID_URL',
    input: '[object Request]'
  }
}

Proposal

createClient should allow providing custom Request and Response constructors, next to fetch.

Checklist

Dzieni avatar Feb 23 '24 12:02 Dzieni

This is a great idea, and I’d be in favor of adding it. msw has a similar concept where there are reasons why you’d have a custom Request or Response that are WHATWG-compliant but have additional helpers or additional behavior. And of course the Node <> browser differences with the fetch() API, which should match but often don’t (and I haven’t done an in-depth comparison on the latest version of Node, but there are almost always subtle differences with APIs that can break edge cases as you’ve found).

drwpow avatar Mar 16 '24 12:03 drwpow

This issue is stale because it has been open for 90 days with no activity. If there is no activity in the next 7 days, the issue will be closed.

github-actions[bot] avatar Aug 06 '24 12:08 github-actions[bot]

This issue was closed because it has been inactive for 7 days since being marked as stale. Please open a new issue if you believe you are encountering a related problem.

github-actions[bot] avatar Aug 14 '24 02:08 github-actions[bot]