-
-
Notifications
You must be signed in to change notification settings - Fork 467
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: add verification when request body is falsy #1702
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good fix! I’m fine merging this without tests as it’s simple enough, but would also love a test that prevents this regressing if possible.
I am getting this error when running pnpm test
> openapi-fetch@0.9.7 pretest /home/eduardo/dev/forks/openapi-typescript/packages/openapi-fetch
> pnpm run generate-types
> openapi-fetch@0.9.7 generate-types /home/eduardo/dev/forks/openapi-typescript/packages/openapi-fetch
> node ./scripts/generate-types.js
file:///home/eduardo/dev/forks/openapi-typescript/node_modules/.pnpm/execa@8.0.1/node_modules/execa/lib/error.js:60
error = new Error(message);
^
Error: Command failed with exit code 1: ../openapi-typescript/bin/cli.js ./test/fixtures/api.yaml -o ./test/fixtures/v7-beta.d.ts
node:internal/modules/esm/resolve:264
throw new ERR_MODULE_NOT_FOUND(
^
Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/home/eduardo/dev/forks/openapi-typescript/packages/openapi-typescript/dist/index.js' imported from /home/eduardo/dev/forks/openapi-typescript/packages/openapi-typescript/bin/cli.js
at finalizeResolution (node:internal/modules/esm/resolve:264:11)
at moduleResolve (node:internal/modules/esm/resolve:917:10)
at defaultResolve (node:internal/modules/esm/resolve:1130:11)
at ModuleLoader.defaultResolve (node:internal/modules/esm/loader:396:12)
at ModuleLoader.resolve (node:internal/modules/esm/loader:365:25)
at ModuleLoader.getModuleJob (node:internal/modules/esm/loader:240:38)
at ModuleWrap.<anonymous> (node:internal/modules/esm/module_job:85:39)
at link (node:internal/modules/esm/module_job:84:36) {
code: 'ERR_MODULE_NOT_FOUND',
url: 'file:///home/eduardo/dev/forks/openapi-typescript/packages/openapi-typescript/dist/index.js'
}
Node.js v20.11.1
at makeError (file:///home/eduardo/dev/forks/openapi-typescript/node_modules/.pnpm/execa@8.0.1/node_modules/execa/lib/error.js:60:11)
at handlePromise (file:///home/eduardo/dev/forks/openapi-typescript/node_modules/.pnpm/execa@8.0.1/node_modules/execa/index.js:124:26)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async Promise.all (index 1)
at async generate (file:///home/eduardo/dev/forks/openapi-typescript/packages/openapi-fetch/scripts/generate-types.js:13:3) {
shortMessage: 'Command failed with exit code 1: ../openapi-typescript/bin/cli.js ./test/fixtures/api.yaml -o ./test/fixtures/v7-beta.d.ts',
command: '../openapi-typescript/bin/cli.js ./test/fixtures/api.yaml -o ./test/fixtures/v7-beta.d.ts',
escapedCommand: '"../openapi-typescript/bin/cli.js" "./test/fixtures/api.yaml" -o "./test/fixtures/v7-beta.d.ts"',
exitCode: 1,
signal: undefined,
signalDescription: undefined,
stdout: '',
stderr: 'node:internal/modules/esm/resolve:264\n' +
' throw new ERR_MODULE_NOT_FOUND(\n' +
' ^\n' +
'\n' +
"Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/home/eduardo/dev/forks/openapi-typescript/packages/openapi-typescript/dist/index.js' imported from /home/eduardo/dev/forks/openapi-typescript/packages/openapi-typescript/bin/cli.js\n" +
' at finalizeResolution (node:internal/modules/esm/resolve:264:11)\n' +
' at moduleResolve (node:internal/modules/esm/resolve:917:10)\n' +
' at defaultResolve (node:internal/modules/esm/resolve:1130:11)\n' +
' at ModuleLoader.defaultResolve (node:internal/modules/esm/loader:396:12)\n' +
' at ModuleLoader.resolve (node:internal/modules/esm/loader:365:25)\n' +
' at ModuleLoader.getModuleJob (node:internal/modules/esm/loader:240:38)\n' +
' at ModuleWrap.<anonymous> (node:internal/modules/esm/module_job:85:39)\n' +
' at link (node:internal/modules/esm/module_job:84:36) {\n' +
" code: 'ERR_MODULE_NOT_FOUND',\n" +
" url: 'file:///home/eduardo/dev/forks/openapi-typescript/packages/openapi-typescript/dist/index.js'\n" +
'}\n' +
'\n' +
'Node.js v20.11.1',
cwd: '/home/eduardo/dev/forks/openapi-typescript/packages/openapi-fetch/',
failed: true,
timedOut: false,
isCanceled: false,
killed: false
}
Node.js v20.11.1
ELIFECYCLE Command failed with exit code 1.
ELIFECYCLE Command failed with exit code 1.
``` |
You’ll need to run The Contributing guide has some additional information on testing locally. |
I am having problems in understanding the trigger for the removal of this header. I am not familiar with the inner workings of this lib. I made the start of a test, but I don't think it's quite it: it("deletes Content-Type header when body is FormData", async () => {
const client = createClient<paths>({ baseUrl });
const formData = new FormData();
formData.append("key", "value");
const { getRequest } = useMockRequestHandler({
baseUrl,
method: "post",
path: "/anyMethod",
status: 200,
body: { success: true },
});
await client.POST("/anyMethod", {
headers: {
"Content-Type": "application/json",
},
});
const req = getRequest();
expect(req).toBeDefined();
expect(req.headers).toBeDefined();
expect(req.headers.has("Content-Type")).toBe(false);
expect(req.body).toBe(formData);
}); |
At a high level, there are 2 ways of interpreting #1694:
This is opinionated, but the first option seems overreaching, and having read a lot of bug reports and strange ways APIs behave, I feel confident that there will likely be some users that have APIs that require For #1695, what we want to accomplish is only set Solving the 2 together, on this line where we initialize the headers, we should just remove that. Unsetting a header is tricky because we don’t know if we set it or the user. So we can just delay setting that in the first place until the actual request (meaning it will be - baseHeaders = mergeHeaders(DEFAULT_HEADERS, baseHeaders); Later, when we create the request object, we are again merging headers (which had the default + if (requestInit.body !== `undefined`) {
+ baseHeaders = mergeHeaders(DEFAULT_HEADERS, baseHeaders);
+ }
+
const requestInit = { Which we couldn’t do earlier, because we didn’t know if there was a body on the request or not. Also, making sure So what we’ve done is just delay the default until later, and IF AND ONLY IF this has a body.
The existing logic is there because we want to have
With the danger here being we accidentally invert the order, and unset Remember that the approach would differ if we had chosen the first option in the beginning—we’d simply delete that header regardless of what the user did. But as that feels more dangerous/unpredictable, we structured our code and the tests to make sure we don’t override users’ opinions, and instead just improve the defaults. |
packages/openapi-fetch/src/index.js
Outdated
@@ -80,7 +80,7 @@ export default function createClient(clientOptions) { | |||
requestInit.body = bodySerializer(requestInit.body); | |||
} | |||
// remove `Content-Type` if serialized body is FormData; browser will correctly set Content-Type & boundary expression | |||
if (requestInit.body instanceof FormData) { | |||
if (requestInit.body && requestInit.body instanceof FormData) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (requestInit.body && requestInit.body instanceof FormData) { | |
if (!requestInit.body || requestInit.body instanceof FormData) { |
altho out of scope for this pr but we should delete the content type when body is empty, currently there's no proper way to remove the body and when I don't need to send any body to backend, backend throws content type json was used but no body provided
Edit: ignore this, for some reason github didn't loaded the above conversations which has discussions related to it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I may have approved prematurely because I didn‘t realize at first this was attempting to solve 2 issues with 1 PR. My suggestions should be a ~2-line change in code, and a couple test additions to satisfy both.
|
@drwpow Do you think it's necessary to perform these tests on this specific PR? I am encountering this bug every time I reinstall this lib, having to change it locally to be able to test my app (with Vitest). Do you think your suggestions can be put into another issue that has a more comprehensive context? The way I see them, they alter the library's behaviour (much more overarching than this simple hotfix). Please, do correct me if I am ignorant about this. |
Yes we can merge as-is, if you’d like. But I mostly asked for tests because in order to fix all the problems outlined in #1694 and #1965, we’d probably have to overwrite your changes here (which would be a slight behavior change, as you pointed out, but IMO nothing significant or breaking). I believe your original issue overlaps a little with those issues, but is actually different. Tests are just good reinforcers that when you write code, it sticks around (because you taking your valuable time to open a PR and fix an issue means a lot! It really does. And this project is only possible from people like yourself. And tests just ensure your good work sticks around). Given the time on this, and the need to fix #1694 and #1695, I’ll merge, and push a fix for those separately. But feel free to open another issue (or another PR) if those changes cause a regression for your scenario. |
* fix: add verification when request body is falsy * Update index.js * style: Update conditional check for FormData instance
Changes
What does this PR change? Link to any related issue(s).
#1695
#1694
How to Review
The
instanceof
was throwing an error when the body was falsy.Checklist
docs/
updated (if necessary)pnpm run update:examples
run (only applicable for openapi-typescript)