Skip to content
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

Payload for "application/x-www-form-urlencoded" is actually for "multipart/form-data" #1441

Open
soulchild opened this issue Feb 15, 2023 · 5 comments
Assignees

Comments

@soulchild
Copy link

I have an OpenAPI specification with a contentType of application/x-www-form-urlencoded:

"/foo": {
  "post": {
    "requestBody": {
      "content": {
        "application/x-www-form-urlencoded": {
          "schema": {
            "$ref": "#/someSchema"
          }
        }
      }
    }
  }
}

This library creates POST data using FormData which ends up being suitable for a contentType of multipart/form-data, not application/x-www-form-urlencoded.

In other words, instead of something like:

parameter1=value1&parameter2=value2

it generates a base64-encoded payload, which decodes to:

----------------------------037807260368578567993227
Content-Disposition: form-data; name="parameter1"

value1
--------------

I believe the FormData needs to be passed through URLSearchParams() to generate a payload suitable for application/x-www-form-urlencoded:

const form = new FormData();
form.append('parameter1', 'value1');
form.append('parameter2', 'value2');
console.log(new URLSearchParams(form).toString());

// 'parameter1=value1&parameter2=value2'

Or am I missing something here? Thanks! 😄

@soulchild
Copy link
Author

Ok, it seems like the types for URLSearchParams correctly don't directly accept FormData, so this only works in plain JS:

microsoft/TypeScript#30584

So some other fix is needed.

@daankets
Copy link

@soulchild I ran into the same problem today, and found a fix by patching the generated services after generation. In case the mediaType is for url-encoded form data, you can replace: formData: formData by body:new URLSearchParams(formData).toString(). I tested it using the node client.

@onurkun
Copy link

onurkun commented Oct 22, 2023

You can create new script to fix with a single liner
find . -type f -exec sed -i.bkp 's/formData: formData/body: new URLSearchParams(formData as Record<string,any>).toString()/' {} \; && find . -iname '*.bkp' -delete

@ttacon
Copy link

ttacon commented Oct 23, 2023

I ran into this today as well, from looking at the code, the request templates all need to become contextually aware of the different potential encoding strategies for Forms based on if the Content-Type is either multipart/form-data or application/x-www-form-urlencoded.

As an example, for clients generated to use axios:

There are two potential, simpler, fixes here - (1) either the mediaType earlier, and passing in the optional userHeaders parameter to form.getHeaders(). e.g.:

	const formHeaders = typeof formData?.getHeaders === 'function' && formData?.getHeaders(
		!!options.mediaType ? { 'Content-Type': options.mediaType} : {},
	) || {}

or (2) alter the order of the object expansion operations:

	const headers = Object.entries({
		Accept: 'application/json',
		...additionalHeaders,
+		...formHeaders,
		...options.headers,
-		...formHeaders,
	})

Of the above two, the former is likely more resilient due to allowing form-data to control the returned type, the latter is a smaller overall change (although, I'm unsure if the original order of having formHeaders last was intentional).

Would either of these solutions be acceptable as a PR?

@jordanshatford
Copy link

Check out our fork of this repository @hey-api/openapi-ts. We have fixed this issue in v0.32.1. If you run into any further issues, open an issue in our repository. Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants