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

toFormData helper function #3757

Merged
merged 3 commits into from Dec 23, 2021
Merged

toFormData helper function #3757

merged 3 commits into from Dec 23, 2021

Conversation

carpben
Copy link
Contributor

@carpben carpben commented Apr 17, 2021

With this functionality we can provide the user an option to pass a data object, instead of building FormData by himself. When the data is nested, building form data isn't trivial, and can result in an inappropriate structure and bugs. Hence usage of this functionality seems more reliable.

The function can handle nested data of the following types: object, array, string, number, boolean, null, undefined, Fiile.

Related feature request thread: #3721

This doesn't deal with the API in which this functionality will be offered to the user.

@jasonsaayman
Copy link
Member

Hi @carpben

Can you maybe ad some documentation to the readme for how this is intended to work and give an example?

Thanks

@carpben
Copy link
Contributor Author

carpben commented May 7, 2021

Hi @jasonsaayman,
I'm not sure yet how this functionality should be used.
The most straight forward way would be to export the toFormData function, and allow the user to use it by himself.

import axios, {toFormData} from "axios"

axios({
  method: "post",
  url: "www.example.com/endpoint",
  data: toFormData(jsObject), 
  headers: { "Content-Type": "multipart/form-data" },
})

@DigitalBrainJS
Copy link
Collaborator

Wouldn't it make more sense to do this conversion automatically if the content type is multipart/form-data and data is a plain object? We can add an option to control this behavior, such as requestType or dataType, or just make it default behavior, temporarily disabled by a transitional option.

@carpben
Copy link
Contributor Author

carpben commented May 7, 2021

@DigitalBrainJS , it does make sense. If we can convert an object to FormData by default if content type is multipart/form-data it would be much more user friendly.

@carpben
Copy link
Contributor Author

carpben commented May 7, 2021

@DigitalBrainJS ,

Perhaps add a request method alias:

axios.postFormData(url, jsDataObject)

So instead of

axios({
  method: "post",
  url: "www.example.com/endpoint",
  data: toFormData(jsObject), 
  headers: { "Content-Type": "multipart/form-data" },
})

The user can use the equivelent:

axios.postFormData("www.example.com/endpoint", jsObject)

@carpben
Copy link
Contributor Author

carpben commented May 29, 2021

@jasonsaayman , @DigitalBrainJS ,
Any thoughts?

@carpben
Copy link
Contributor Author

carpben commented Jul 19, 2021

@jasonsaayman, Which direction do you think we should go in?

  1. Export toFormData directly (see code above)
  2. Add request method alias axios.postFormData (See code above)
  3. Folow @DigitalBrainJS suggestion - conver object to formData if content type is multipart/form-data

@jasonsaayman jasonsaayman merged commit 9964815 into axios:master Dec 23, 2021
@caugner
Copy link
Contributor

caugner commented Jan 18, 2022

@carpben @jasonsaayman The release notes mention this toFormData helper function, which is very promising, but it doesn't seem to be exported to be used outside of axios?

@jasonsaayman
Copy link
Member

Oh darn, I must have forgotten to do this, I wanted to ask @carpben to do it but clean forgot and then forgot myself too, I will update a pull request for that.

@carpben
Copy link
Contributor Author

carpben commented Jan 19, 2022

Thanks @caugner.
@jasonsaayman there is one thing we should address. Current solution won't work for node, as FormData is not available there natively.
Can we import 'form-data' if running in node?
Would be happy to prepare a PR.

@DigitalBrainJS
Copy link
Collaborator

It seems that the mix of 1 + 3 options is the best solution we can find here.
Axios already processes payload as JSON if the content type is application/json, and it would be logical to add a formData resolver for the multipart/form-data case too.
plainObject && multipart/form-data => stringify as FormData
plainObject || application/json => stringify as json

So we can just replace

axios/lib/defaults.js

Lines 74 to 77 in 1163588

if (utils.isObject(data) || (headers && headers['Content-Type'] === 'application/json')) {
setContentTypeIfUnset(headers, 'application/json');
return stringifySafely(data);
}

with

var isObjectPayload = utils.isObject(data);
var contentType = headers && headers['Content-Type'];

if ( isObjectPayload && contentType === 'multipart/form-data' ) {
  return toFormData(data);
} else if ( isObjectPayload || contentType === 'application/json' ){
  setContentTypeIfUnset(headers, 'application/json');
  return stringifySafely(data);
}

@michael-land
Copy link
Contributor

is this only work on browser?

Does nodejs native support global.FormData? I don't see any imports from the form-data package.

@carpben
Copy link
Contributor Author

carpben commented Jan 21, 2022

@xiaoyu-tamu as far as I know global.FormData is undefined. Currently toFormData is only supported in the browser. Adding support should be pretty straight forward by using form-data as a dependency.

@carpben
Copy link
Contributor Author

carpben commented Jan 21, 2022

@DigitalBrainJS I agree this is the right direction. But I'd rather wait with it for a bit.

  1. Solve Node case first
  2. Promote usage of toFormData in docs and elsewhere
  3. See how it is adopted by the community. Are there any bug reports or feature related requests?

Consider if you suggested change is a breaking change.
Could it be that some users inappropriately send a request with:

data instanceof FormData // false 
contentType // 'multipart/form-data'

And for their requests to somehow be successful?

@ankurk91
Copy link

I have been using this package in past

https://www.npmjs.com/package/object-to-formdata

@carpben
Copy link
Contributor Author

carpben commented Jan 23, 2022

I was not aware of object-to-formdata. There are 2 aspects the package supports that we currently don't:

  • bracket notation for nested values.
  • Date type.
    Perhaps we can consider it in the future. Thanks for sharing this @ankurk91 !

@jasonsaayman
Copy link
Member

@DigitalBrainJS can you look at the package mentioned and see if we would rather look into that? We can add that but there is a cost that might be a bit high, I am in favour at looking at native support for it's feature set

mbargiel pushed a commit to mbargiel/axios that referenced this pull request Jan 27, 2022
* adding toFormData test

* adding toFormData

Co-authored-by: Jay <jasonsaayman@gmail.com>
@carpben carpben mentioned this pull request Feb 4, 2022
@saschagehlich
Copy link

I believe this change causes axios to not recognize FormData objects in react-native. I stumbled over this issue after updating axios to the latest version. Suddenly, axios started stringifying FormData objects.

For everyone finding this, here's a workaround to making it work. Add this to your request's options, formData being your FormData object:

{
    transformRequest: (data, headers) => {
        return formData;
    },
}

This causes axios to not transform your data.

@radko93
Copy link

radko93 commented Mar 29, 2022

Thanks a lot @saschagehlich, this is completely breaking React Native form data requests.

@myrs
Copy link

myrs commented Mar 31, 2022

Thanks @saschagehlich, this broke my requests in react-native as well! Actually, as mentioned here, the workaround can be even more concise:

{
  //..
  transformRequest: data => data
  //..
}

I've tested on react-native=0.67.4 and axios=0.26.1 and it works.

@carpben
Copy link
Contributor Author

carpben commented Apr 2, 2022

@saschagehlich The issue was probably caused by a different change (change to isFormData detection). It was fixed by #4448 (not published yet, should be soon).

@jasonsaayman
Copy link
Member

Working on the release will be done asap, just trying to get a couple things done and try not introduce any breaking changes on 0.26.2

ksibisamir added a commit to SaTT-Wallet/Backend that referenced this pull request May 26, 2023
<h3>Snyk has created this PR to upgrade axios from 0.26.1 to
0.27.2.</h3>

:information_source: Keep your dependencies up-to-date. This makes it
easier to fix existing vulnerabilities and to more quickly identify and
fix newly disclosed vulnerabilities when they affect your project.
<hr/>

- The recommended version is **3 versions** ahead of your current
version.
- The recommended version was released **a year ago**, on 2022-04-27.


<details>
<summary><b>Release notes</b></summary>
<br/>
  <details>
    <summary>Package name: <b>axios</b></summary>
    <ul>
      <li>
<b>0.27.2</b> - <a
href="https://snyk.io/redirect/github/axios/axios/releases/tag/v0.27.2">2022-04-27</a></br><p>Fixes
and Functionality:</p>
<ul>
<li>Fixed FormData posting in browser environment by reverting <a
class="issue-link js-issue-link" data-error-text="Failed to load title"
data-id="878655062" data-permission-text="Title is private"
data-url="axios/axios#3785"
data-hovercard-type="pull_request"
data-hovercard-url="/axios/axios/pull/3785/hovercard"
href="https://snyk.io/redirect/github/axios/axios/pull/3785">#3785</a>
(<a href="https://snyk.io/redirect/github/axios/axios/pull/4640"
data-hovercard-type="pull_request"
data-hovercard-url="/axios/axios/pull/4640/hovercard">#4640</a>)</li>
<li>Enhanced protocol parsing implementation (<a
href="https://snyk.io/redirect/github/axios/axios/pull/4639"
data-hovercard-type="pull_request"
data-hovercard-url="/axios/axios/pull/4639/hovercard">#4639</a>)</li>
<li>Fixed bundle size</li>
</ul>
      </li>
      <li>
<b>0.27.1</b> - <a
href="https://snyk.io/redirect/github/axios/axios/releases/tag/v0.27.1">2022-04-26</a></br><h3>Fixes
and Functionality:</h3>
<ul>
<li>Removed import of url module in browser build due to huge size
overhead and builds being broken (<a
href="https://snyk.io/redirect/github/axios/axios/pull/4594"
data-hovercard-type="pull_request"
data-hovercard-url="/axios/axios/pull/4594/hovercard">#4594</a>)</li>
<li>Bumped follow-redirects to ^1.14.9 (<a
href="https://snyk.io/redirect/github/axios/axios/pull/4615"
data-hovercard-type="pull_request"
data-hovercard-url="/axios/axios/pull/4615/hovercard">#4615</a>)</li>
</ul>
      </li>
      <li>
<b>0.27.0</b> - <a
href="https://snyk.io/redirect/github/axios/axios/releases/tag/v0.27.0">2022-04-25</a></br><h3>Breaking
changes:</h3>
<ul>
<li>New toFormData helper function that allows the implementor to pass
an object and allow axios to convert it to FormData (<a
href="https://snyk.io/redirect/github/axios/axios/pull/3757"
data-hovercard-type="pull_request"
data-hovercard-url="/axios/axios/pull/3757/hovercard">#3757</a>)</li>
<li>Removed functionality that removed the the <code>Content-Type</code>
request header when passing FormData (<a
href="https://snyk.io/redirect/github/axios/axios/pull/3785"
data-hovercard-type="pull_request"
data-hovercard-url="/axios/axios/pull/3785/hovercard">#3785</a>)</li>
<li><strong>(*)</strong> Refactored error handling implementing
AxiosError as a constructor, this is a large change to error handling on
the whole (<a
href="https://snyk.io/redirect/github/axios/axios/pull/3645"
data-hovercard-type="pull_request"
data-hovercard-url="/axios/axios/pull/3645/hovercard">#3645</a>)</li>
<li>Separated responsibility for FormData instantiation between
<code>transformRequest</code> and <code>toFormData</code> (<a
href="https://snyk.io/redirect/github/axios/axios/pull/4470"
data-hovercard-type="pull_request"
data-hovercard-url="/axios/axios/pull/4470/hovercard">#4470</a>)</li>
<li><strong>(*)</strong> Improved and fixed multiple issues with
FormData support (<a
href="https://snyk.io/redirect/github/axios/axios/pull/4448"
data-hovercard-type="pull_request"
data-hovercard-url="/axios/axios/pull/4448/hovercard">#4448</a>)</li>
</ul>
<h3>QOL and DevX improvements:</h3>
<ul>
<li>Added a multipart/form-data testing playground allowing contributors
to debug changes easily (<a
href="https://snyk.io/redirect/github/axios/axios/pull/4465"
data-hovercard-type="pull_request"
data-hovercard-url="/axios/axios/pull/4465/hovercard">#4465</a>)</li>
</ul>
<h3>Fixes and Functionality:</h3>
<ul>
<li>Refactored project file structure to avoid circular imports (<a
href="https://snyk.io/redirect/github/axios/axios/pull/4516"
data-hovercard-type="pull_request"
data-hovercard-url="/axios/axios/pull/4516/hovercard">#4515</a>) &amp;
(<a href="https://snyk.io/redirect/github/axios/axios/pull/4516"
data-hovercard-type="pull_request"
data-hovercard-url="/axios/axios/pull/4516/hovercard">#4516</a>)</li>
<li>Bumped follow-redirects to ^1.14.9 (<a
href="https://snyk.io/redirect/github/axios/axios/pull/4562"
data-hovercard-type="pull_request"
data-hovercard-url="/axios/axios/pull/4562/hovercard">#4562</a>)</li>
</ul>
<h3>Internal and Tests:</h3>
<ul>
<li>Updated dev dependencies to latest version</li>
</ul>
<h3>Documentation:</h3>
<ul>
<li>Fixing incorrect link in changelog (<a
href="https://snyk.io/redirect/github/axios/axios/pull/4551"
data-hovercard-type="pull_request"
data-hovercard-url="/axios/axios/pull/4551/hovercard">#4551</a>)</li>
</ul>
<h3>Notes:</h3>
<ul>
<li><strong>(*)</strong> Please read these pull requests before
updating, these changes are very impactful and far reaching.</li>
</ul>
      </li>
      <li>
<b>0.26.1</b> - <a
href="https://snyk.io/redirect/github/axios/axios/releases/tag/v0.26.1">2022-03-09</a></br><h3>Fixes
and Functionality:</h3>
<ul>
<li>Refactored project file structure to avoid circular imports (<a
href="https://snyk.io/redirect/github/axios/axios/pull/4220"
data-hovercard-type="pull_request"
data-hovercard-url="/axios/axios/pull/4220/hovercard">#4220</a>)</li>
</ul>
      </li>
    </ul>
from <a
href="https://snyk.io/redirect/github/axios/axios/releases">axios GitHub
release notes</a>
  </details>
</details>
<hr/>

**Note:** *You are seeing this because you or someone else with access
to this repository has authorized Snyk to open upgrade PRs.*

For more information: <img
src="https://api.segment.io/v1/pixel/track?data=eyJ3cml0ZUtleSI6InJyWmxZcEdHY2RyTHZsb0lYd0dUcVg4WkFRTnNCOUEwIiwiYW5vbnltb3VzSWQiOiIyMDVhZWJmMC01NTE3LTQ2ZjQtODg0Zi0xYjEwZjdiOWU3YjgiLCJldmVudCI6IlBSIHZpZXdlZCIsInByb3BlcnRpZXMiOnsicHJJZCI6IjIwNWFlYmYwLTU1MTctNDZmNC04ODRmLTFiMTBmN2I5ZTdiOCJ9fQ=="
width="0" height="0"/>

🧐 [View latest project
report](https://app.snyk.io/org/satt/project/b89486be-ad07-4d6c-a51a-2fa8a25baa00?utm_source&#x3D;github&amp;utm_medium&#x3D;referral&amp;page&#x3D;upgrade-pr)

🛠 [Adjust upgrade PR
settings](https://app.snyk.io/org/satt/project/b89486be-ad07-4d6c-a51a-2fa8a25baa00/settings/integration?utm_source&#x3D;github&amp;utm_medium&#x3D;referral&amp;page&#x3D;upgrade-pr)

🔕 [Ignore this dependency or unsubscribe from future upgrade
PRs](https://app.snyk.io/org/satt/project/b89486be-ad07-4d6c-a51a-2fa8a25baa00/settings/integration?pkg&#x3D;axios&amp;utm_source&#x3D;github&amp;utm_medium&#x3D;referral&amp;page&#x3D;upgrade-pr#auto-dep-upgrades)

<!---
(snyk:metadata:{"prId":"205aebf0-5517-46f4-884f-1b10f7b9e7b8","prPublicId":"205aebf0-5517-46f4-884f-1b10f7b9e7b8","dependencies":[{"name":"axios","from":"0.26.1","to":"0.27.2"}],"packageManager":"npm","type":"auto","projectUrl":"https://app.snyk.io/org/satt/project/b89486be-ad07-4d6c-a51a-2fa8a25baa00?utm_source=github&utm_medium=referral&page=upgrade-pr","projectPublicId":"b89486be-ad07-4d6c-a51a-2fa8a25baa00","env":"prod","prType":"upgrade","vulns":[],"issuesToFix":[],"upgrade":[],"upgradeInfo":{"versionsDiff":3,"publishedDate":"2022-04-27T10:00:58.685Z"},"templateVariants":[],"hasFixes":false,"isMajorUpgrade":false,"isBreakingChange":false,"priorityScoreList":[]})
--->
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

Successfully merging this pull request may close these issues.

None yet

9 participants