mirror of
https://github.com/axios/axios.git
synced 2026-04-11 14:21:59 +08:00
Added axios.formToJSON method; (#4735)
* Draft * Added `formDataToJSON` helper; Added `axios.formToJSON` method; Added client tests; Co-authored-by: Jay <jasonsaayman@gmail.com>
This commit is contained in:
parent
934f390cc3
commit
c008e57fe4
7
index.d.ts
vendored
7
index.d.ts
vendored
@ -300,6 +300,12 @@ export interface GenericFormData {
|
||||
append(name: string, value: any, options?: any): any;
|
||||
}
|
||||
|
||||
export interface GenericHTMLFormElement {
|
||||
name: string;
|
||||
method: string;
|
||||
submit(): void;
|
||||
}
|
||||
|
||||
export interface AxiosStatic extends AxiosInstance {
|
||||
create(config?: CreateAxiosDefaults): AxiosInstance;
|
||||
Cancel: CancelStatic;
|
||||
@ -312,6 +318,7 @@ export interface AxiosStatic extends AxiosInstance {
|
||||
spread<T, R>(callback: (...args: T[]) => R): (array: T[]) => R;
|
||||
isAxiosError<T = any, D = any>(payload: any): payload is AxiosError<T, D>;
|
||||
toFormData(sourceObj: object, targetFormData?: GenericFormData, options?: FormSerializerOptions): GenericFormData;
|
||||
formToJSON(form: GenericFormData|GenericHTMLFormElement): object;
|
||||
}
|
||||
|
||||
declare const axios: AxiosStatic;
|
||||
|
||||
@ -5,7 +5,7 @@ var bind = require('./helpers/bind');
|
||||
var Axios = require('./core/Axios');
|
||||
var mergeConfig = require('./core/mergeConfig');
|
||||
var defaults = require('./defaults');
|
||||
|
||||
var formDataToJSON = require('./helpers/formDataToJSON');
|
||||
/**
|
||||
* Create an instance of Axios
|
||||
*
|
||||
@ -58,6 +58,10 @@ axios.spread = require('./helpers/spread');
|
||||
// Expose isAxiosError
|
||||
axios.isAxiosError = require('./helpers/isAxiosError');
|
||||
|
||||
axios.formToJSON = function(thing) {
|
||||
return formDataToJSON(utils.isHTMLForm(thing) ? new FormData(thing) : thing);
|
||||
};
|
||||
|
||||
module.exports = axios;
|
||||
|
||||
// Allow use of default import syntax in TypeScript
|
||||
|
||||
@ -25,7 +25,8 @@ function Axios(instanceConfig) {
|
||||
/**
|
||||
* Dispatch a request
|
||||
*
|
||||
* @param {Object} config The config specific for this request (merged with this.defaults)
|
||||
* @param {String|Object} configOrUrl The config specific for this request (merged with this.defaults)
|
||||
* @param {?Object} config
|
||||
*/
|
||||
Axios.prototype.request = function request(configOrUrl, config) {
|
||||
/*eslint no-param-reassign:0*/
|
||||
|
||||
@ -7,6 +7,7 @@ var transitionalDefaults = require('./transitional');
|
||||
var toFormData = require('../helpers/toFormData');
|
||||
var toURLEncodedForm = require('../helpers/toURLEncodedForm');
|
||||
var platform = require('../platform');
|
||||
var formDataToJSON = require('../helpers/formDataToJSON');
|
||||
|
||||
var DEFAULT_CONTENT_TYPE = {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
@ -55,8 +56,24 @@ var defaults = {
|
||||
normalizeHeaderName(headers, 'Accept');
|
||||
normalizeHeaderName(headers, 'Content-Type');
|
||||
|
||||
if (utils.isFormData(data) ||
|
||||
utils.isArrayBuffer(data) ||
|
||||
var contentType = headers && headers['Content-Type'] || '';
|
||||
var hasJSONContentType = contentType.indexOf('application/json') > -1;
|
||||
var isObjectPayload = utils.isObject(data);
|
||||
|
||||
if (isObjectPayload && utils.isHTMLForm(data)) {
|
||||
data = new FormData(data);
|
||||
}
|
||||
|
||||
var isFormData = utils.isFormData(data);
|
||||
|
||||
if (isFormData) {
|
||||
if (!hasJSONContentType) {
|
||||
return data;
|
||||
}
|
||||
return hasJSONContentType ? JSON.stringify(formDataToJSON(data)) : data;
|
||||
}
|
||||
|
||||
if (utils.isArrayBuffer(data) ||
|
||||
utils.isBuffer(data) ||
|
||||
utils.isStream(data) ||
|
||||
utils.isFile(data) ||
|
||||
@ -72,8 +89,6 @@ var defaults = {
|
||||
return data.toString();
|
||||
}
|
||||
|
||||
var isObjectPayload = utils.isObject(data);
|
||||
var contentType = headers && headers['Content-Type'] || '';
|
||||
var isFileList;
|
||||
|
||||
if (isObjectPayload) {
|
||||
@ -81,7 +96,7 @@ var defaults = {
|
||||
return toURLEncodedForm(data, this.formSerializer).toString();
|
||||
}
|
||||
|
||||
if ((isFileList = utils.isFileList(data)) || contentType.indexOf('multipart/form-data') !== -1) {
|
||||
if ((isFileList = utils.isFileList(data)) || contentType.indexOf('multipart/form-data') > -1) {
|
||||
var _FormData = this.env && this.env.FormData;
|
||||
|
||||
return toFormData(
|
||||
@ -92,7 +107,7 @@ var defaults = {
|
||||
}
|
||||
}
|
||||
|
||||
if (isObjectPayload || contentType.indexOf('application/json') !== -1) {
|
||||
if (isObjectPayload || hasJSONContentType ) {
|
||||
setContentTypeIfUnset(headers, 'application/json');
|
||||
return stringifySafely(data);
|
||||
}
|
||||
|
||||
71
lib/helpers/formDataToJSON.js
Normal file
71
lib/helpers/formDataToJSON.js
Normal file
@ -0,0 +1,71 @@
|
||||
'use strict';
|
||||
|
||||
var utils = require('../utils');
|
||||
|
||||
function parsePropPath(name) {
|
||||
// foo[x][y][z]
|
||||
// foo.x.y.z
|
||||
// foo-x-y-z
|
||||
// foo x y z
|
||||
return utils.matchAll(/\w+|\[(\w*)]/g, name).map(function(match) {
|
||||
return match[0] === '[]' ? '' : match[1] || match[0];
|
||||
});
|
||||
}
|
||||
|
||||
function arrayToObject(arr) {
|
||||
var obj = {};
|
||||
var keys = Object.keys(arr);
|
||||
var i;
|
||||
var len = keys.length;
|
||||
var key;
|
||||
for (i = 0; i < len; i++) {
|
||||
key = keys[i];
|
||||
obj[key] = arr[key];
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
function formDataToJSON(formData) {
|
||||
function buildPath(path, value, target, index) {
|
||||
var name = path[index++];
|
||||
var isNumericKey = Number.isFinite(+name);
|
||||
var isLast = index >= path.length;
|
||||
name = !name && utils.isArray(target) ? target.length : name;
|
||||
|
||||
if (isLast) {
|
||||
if (utils.hasOwnProperty(target, name)) {
|
||||
target[name] = [target[name], value];
|
||||
} else {
|
||||
target[name] = value;
|
||||
}
|
||||
|
||||
return !isNumericKey;
|
||||
}
|
||||
|
||||
if (!target[name] || !utils.isObject(target[name])) {
|
||||
target[name] = [];
|
||||
}
|
||||
|
||||
var result = buildPath(path, value, target[name], index);
|
||||
|
||||
if (result && utils.isArray(target[name])) {
|
||||
target[name] = arrayToObject(target[name]);
|
||||
}
|
||||
|
||||
return !isNumericKey;
|
||||
}
|
||||
|
||||
if (utils.isFormData(formData) && utils.isFunction(formData.entries)) {
|
||||
var obj = {};
|
||||
|
||||
utils.forEachEntry(formData, function(name, value) {
|
||||
buildPath(parsePropPath(name), value, obj, 0);
|
||||
});
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
module.exports = formDataToJSON;
|
||||
38
lib/utils.js
38
lib/utils.js
@ -441,6 +441,38 @@ var isTypedArray = (function(TypedArray) {
|
||||
};
|
||||
})(typeof Uint8Array !== 'undefined' && Object.getPrototypeOf(Uint8Array));
|
||||
|
||||
function forEachEntry(obj, fn) {
|
||||
var generator = obj && obj[Symbol.iterator];
|
||||
|
||||
var iterator = generator.call(obj);
|
||||
|
||||
var result;
|
||||
|
||||
while ((result = iterator.next()) && !result.done) {
|
||||
var pair = result.value;
|
||||
fn.call(obj, pair[0], pair[1]);
|
||||
}
|
||||
}
|
||||
|
||||
function matchAll(regExp, str) {
|
||||
var matches;
|
||||
var arr = [];
|
||||
|
||||
while ((matches = regExp.exec(str)) !== null) {
|
||||
arr.push(matches);
|
||||
}
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
var isHTMLForm = kindOfTest('HTMLFormElement');
|
||||
|
||||
var hasOwnProperty = (function resolver(_hasOwnProperty) {
|
||||
return function(obj, prop) {
|
||||
return _hasOwnProperty.call(obj, prop);
|
||||
};
|
||||
})(Object.prototype.hasOwnProperty);
|
||||
|
||||
module.exports = {
|
||||
isArray: isArray,
|
||||
isArrayBuffer: isArrayBuffer,
|
||||
@ -471,5 +503,9 @@ module.exports = {
|
||||
endsWith: endsWith,
|
||||
toArray: toArray,
|
||||
isTypedArray: isTypedArray,
|
||||
isFileList: isFileList
|
||||
isFileList: isFileList,
|
||||
forEachEntry: forEachEntry,
|
||||
matchAll: matchAll,
|
||||
isHTMLForm: isHTMLForm,
|
||||
hasOwnProperty: hasOwnProperty
|
||||
};
|
||||
|
||||
50
test/specs/helpers/formDataToJSON.spec.js
Normal file
50
test/specs/helpers/formDataToJSON.spec.js
Normal file
@ -0,0 +1,50 @@
|
||||
var formDataToJSON = require('../../../lib/helpers/formDataToJSON');
|
||||
|
||||
describe('formDataToJSON', function () {
|
||||
it('should convert a FormData Object to JSON Object', function () {
|
||||
const formData = new FormData();
|
||||
|
||||
formData.append('foo[bar][baz]', '123');
|
||||
|
||||
expect(formDataToJSON(formData)).toEqual({
|
||||
foo: {
|
||||
bar: {
|
||||
baz: '123'
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should convert repeatable values as an array', function () {
|
||||
const formData = new FormData();
|
||||
|
||||
formData.append('foo', '1');
|
||||
formData.append('foo', '2');
|
||||
|
||||
expect(formDataToJSON(formData)).toEqual({
|
||||
foo: ['1', '2']
|
||||
});
|
||||
});
|
||||
|
||||
it('should convert props with empty brackets to arrays', function () {
|
||||
const formData = new FormData();
|
||||
|
||||
formData.append('foo[]', '1');
|
||||
formData.append('foo[]', '2');
|
||||
|
||||
expect(formDataToJSON(formData)).toEqual({
|
||||
foo: ['1', '2']
|
||||
});
|
||||
});
|
||||
|
||||
it('should supported indexed arrays', function () {
|
||||
const formData = new FormData();
|
||||
|
||||
formData.append('foo[0]', '1');
|
||||
formData.append('foo[1]', '2');
|
||||
|
||||
expect(formDataToJSON(formData)).toEqual({
|
||||
foo: ['1', '2']
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -25,7 +25,8 @@ describe('instance', function () {
|
||||
'isAxiosError',
|
||||
'VERSION',
|
||||
'default',
|
||||
'toFormData'
|
||||
'toFormData',
|
||||
'formToJSON'
|
||||
].indexOf(prop) > -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user