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

Improved FormData support; #4448

Merged
merged 12 commits into from Mar 14, 2022
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
107 changes: 78 additions & 29 deletions README.md
Expand Up @@ -22,7 +22,7 @@ Promise based HTTP client for the browser and node.js
- [Example](#example)
- [Axios API](#axios-api)
- [Request method aliases](#request-method-aliases)
- [Concurrency (Deprecated)](#concurrency-deprecated)
- [Concurrency 👎](#concurrency-deprecated)
- [Creating an instance](#creating-an-instance)
- [Instance methods](#instance-methods)
- [Request Config](#request-config)
Expand All @@ -35,11 +35,15 @@ Promise based HTTP client for the browser and node.js
- [Multiple Interceptors](#multiple-interceptors)
- [Handling Errors](#handling-errors)
- [Cancellation](#cancellation)
- [AbortController](#abortcontroller)
- [CancelToken 👎](#canceltoken-deprecated)
- [Using application/x-www-form-urlencoded format](#using-applicationx-www-form-urlencoded-format)
- [Browser](#browser)
- [Node.js](#nodejs)
- [Query string](#query-string)
- [Form data](#form-data)
- [Automatic serialization](#-automatic-serialization)
- [Manual FormData passing](#manual-formdata-passing)
- [Semver](#semver)
- [Promises](#promises)
- [TypeScript](#typescript)
Expand Down Expand Up @@ -482,6 +486,11 @@ These are the available config options for making requests. Only the `url` is re

// throw ETIMEDOUT error instead of generic ECONNABORTED on request timeouts
clarifyTimeoutError: false,
},

env: {
// The FormData class to be used to automatically serialize the payload into a FormData object
FormData: window?.FormData || global?.FormData
}
}
```
Expand Down Expand Up @@ -706,10 +715,30 @@ axios.get('/user/12345')

## Cancellation

You can cancel a request using a *cancel token*.
### AbortController

Starting from `v0.22.0` Axios supports AbortController to cancel requests in fetch API way:

```js
const controller = new AbortController();

axios.get('/foo/bar', {
signal: controller.signal
}).then(function(response) {
//...
});
// cancel the request
controller.abort()
```

### CancelToken `👎deprecated`

You can also cancel a request using a *CancelToken*.

> The axios cancel token API is based on the withdrawn [cancelable promises proposal](https://github.com/tc39/proposal-cancelable-promises).

> This API is deprecated since v0.22.0 and shouldn't be used in new projects

You can create a cancel token using the `CancelToken.source` factory as shown below:

```js
Expand Down Expand Up @@ -753,22 +782,11 @@ axios.get('/user/12345', {
cancel();
```

Axios supports AbortController to abort requests in [`fetch API`](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API#aborting_a_fetch) way:
```js
const controller = new AbortController();

axios.get('/foo/bar', {
signal: controller.signal
}).then(function(response) {
//...
});
// cancel the request
controller.abort()
```

> Note: you can cancel several requests with the same cancel token/abort controller.
> If a cancellation token is already cancelled at the moment of starting an Axios request, then the request is cancelled immediately, without any attempts to make real request.

> During the transition period, you can use both cancellation APIs, even for the same request:

## Using application/x-www-form-urlencoded format

By default, axios serializes JavaScript objects to `JSON`. To send data in the `application/x-www-form-urlencoded` format instead, you can use one of the following options.
Expand Down Expand Up @@ -828,11 +846,53 @@ axios.post('http://something.com/', params.toString());

You can also use the [`qs`](https://github.com/ljharb/qs) library.

###### NOTE
The `qs` library is preferable if you need to stringify nested objects, as the `querystring` method has known issues with that use case (https://github.com/nodejs/node-v0.x-archive/issues/1665).
> NOTE:
> The `qs` library is preferable if you need to stringify nested objects, as the `querystring` method has [known issues](https://github.com/nodejs/node-v0.x-archive/issues/1665) with that use case.

#### Form data

##### 🆕 Automatic serialization

Starting from `v0.26.0`, Axios supports automatic object serialization to a FormData object if the request `Content-Type`
header is set to `multipart/form-data`.

The following request will submit the data object as a form (Browser & Node.js):
DigitalBrainJS marked this conversation as resolved.
Show resolved Hide resolved

```js
import axios from 'axios';

axios.post('https://postman-echo.com/post', {x: 1}, {
headers: {
'Content-Type': 'multipart/form-data'
}
}).then(({data})=> console.log(data));
```

In the `node.js` build, the ([`form-data`](https://github.com/form-data/form-data)) polyfill is used by default.

You can overload the FormData class by setting the `env.FormData` config variable,
but you probably won't need it in most cases:

```js
const axios= require('axios');
var FormData = require('form-data');

// OR
// axios.defaults.env.FormData= FormData;

axios.post('https://postman-echo.com/post', {x: 1, buf: new Buffer(10)}, {
headers: {
'Content-Type': 'multipart/form-data'
},

env: { // OR
FormData
}
}).then(({data})=> console.log(data));
```

##### Manual FormData passing
DigitalBrainJS marked this conversation as resolved.
Show resolved Hide resolved

In node.js, you can use the [`form-data`](https://github.com/form-data/form-data) library as follows:

```js
Expand All @@ -843,18 +903,7 @@ form.append('my_field', 'my value');
form.append('my_buffer', new Buffer(10));
form.append('my_file', fs.createReadStream('/foo/bar.jpg'));

axios.post('https://example.com', form, { headers: form.getHeaders() })
```

Alternatively, use an interceptor:

```js
axios.interceptors.request.use(config => {
if (config.data instanceof FormData) {
Object.assign(config.headers, config.data.getHeaders());
}
return config;
});
axios.post('https://example.com', form)
```

## Semver
Expand Down
4 changes: 3 additions & 1 deletion lib/defaults.js
Expand Up @@ -120,7 +120,9 @@ var defaults = {
maxContentLength: -1,
maxBodyLength: -1,

env: {},
env: {
FormData: require('./defaults/env/FormData')
},

validateStatus: function validateStatus(status) {
return status >= 200 && status < 300;
Expand Down
2 changes: 2 additions & 0 deletions lib/defaults/env/FormData.js
@@ -0,0 +1,2 @@
// eslint-disable-next-line strict
module.exports = require('form-data');
2 changes: 2 additions & 0 deletions lib/helpers/null.js
@@ -0,0 +1,2 @@
// eslint-disable-next-line strict
module.exports = null;