Convert between different data formats including FormData, JSON, and URL-encoded data with extensive serialization options, configuration merging, and adapter selection.
Convert JavaScript objects to FormData with advanced serialization options for file uploads and form submissions.
/**
* Convert object to FormData with serialization options
* @param sourceObj - Object to convert to FormData
* @param targetFormData - Existing FormData to append to (optional)
* @param options - Serialization configuration options
* @returns FormData instance with serialized object data
*/
axios.toFormData(
sourceObj: object,
targetFormData?: GenericFormData,
options?: FormSerializerOptions
): GenericFormData;
interface FormSerializerOptions extends SerializerOptions {
/** Custom visitor function for object traversal */
visitor?: SerializerVisitor;
/** Use dot notation for nested objects */
dots?: boolean;
/** Include meta tokens in keys */
metaTokens?: boolean;
/** Use array indexes in keys */
indexes?: boolean | null;
}
interface SerializerVisitor {
(
this: GenericFormData,
value: any,
key: string | number,
path: null | Array<string | number>,
helpers: FormDataVisitorHelpers
): boolean;
}
interface GenericFormData {
append(name: string, value: any, options?: any): any;
}Usage Examples:
import axios from "axios";
// Basic object to FormData conversion
const userData = {
name: "John Doe",
email: "john@example.com",
age: 30,
avatar: fileInput.files[0] // File object
};
const formData = axios.toFormData(userData);
// Send as multipart/form-data
await axios.post("/api/users", formData, {
headers: { "Content-Type": "multipart/form-data" }
});
// Nested object conversion with dots notation
const complexData = {
user: {
profile: {
name: "Alice",
settings: {
theme: "dark",
notifications: true
}
}
},
files: [file1, file2]
};
const formDataWithDots = axios.toFormData(complexData, undefined, {
dots: true,
indexes: true
});
// Results in FormData with keys like:
// user.profile.name = "Alice"
// user.profile.settings.theme = "dark"
// files[0] = file1
// files[1] = file2
// Custom visitor for advanced serialization
const customFormData = axios.toFormData(data, undefined, {
visitor: function(value, key, path, helpers) {
if (value instanceof Date) {
this.append(key, value.toISOString());
return false; // Don't continue default processing
}
if (typeof value === "boolean") {
this.append(key, value ? "1" : "0");
return false;
}
return helpers.defaultVisitor.call(this, value, key, path, helpers);
}
});Convert FormData or HTML form elements back to JSON objects.
/**
* Convert FormData or HTMLFormElement to JSON object
* @param form - FormData instance or HTML form element
* @returns Plain JavaScript object with form data
*/
axios.formToJSON(form: GenericFormData | GenericHTMLFormElement): object;
interface GenericHTMLFormElement {
name: string;
method: string;
submit(): void;
}Usage Examples:
// Convert FormData to JSON
const formData = new FormData();
formData.append("name", "John");
formData.append("email", "john@example.com");
formData.append("age", "30");
const jsonData = axios.formToJSON(formData);
console.log(jsonData); // { name: "John", email: "john@example.com", age: "30" }
// Convert HTML form to JSON
const formElement = document.getElementById("user-form");
const formJson = axios.formToJSON(formElement);
// Use in request
await axios.post("/api/users", formJson);
// Handle complex form structures
const complexForm = new FormData();
complexForm.append("user[name]", "Alice");
complexForm.append("user[email]", "alice@example.com");
complexForm.append("preferences[theme]", "dark");
complexForm.append("tags[]", "admin");
complexForm.append("tags[]", "user");
const parsedData = axios.formToJSON(complexForm);
// Results in nested object structure based on form field namesMerge multiple axios configurations with intelligent precedence handling.
/**
* Merge two axios configurations intelligently
* @param config1 - Base configuration
* @param config2 - Override configuration
* @returns Merged configuration with proper precedence
*/
axios.mergeConfig<D = any>(
config1: AxiosRequestConfig<D>,
config2: AxiosRequestConfig<D>
): AxiosRequestConfig<D>;Usage Examples:
// Base configuration
const baseConfig = {
baseURL: "https://api.example.com",
timeout: 5000,
headers: {
"Accept": "application/json",
"User-Agent": "MyApp/1.0"
},
params: {
version: "v1"
}
};
// Override configuration
const requestConfig = {
timeout: 10000, // Override timeout
headers: {
"Authorization": "Bearer token123", // Add new header
"Accept": "application/json, text/plain" // Override accept
},
params: {
limit: 10 // Add new parameter
}
};
const merged = axios.mergeConfig(baseConfig, requestConfig);
console.log(merged);
/* Result:
{
baseURL: "https://api.example.com",
timeout: 10000, // Overridden
headers: {
"Accept": "application/json, text/plain", // Overridden
"User-Agent": "MyApp/1.0", // Preserved
"Authorization": "Bearer token123" // Added
},
params: {
version: "v1", // Preserved
limit: 10 // Added
}
}
*/
// Use in instance creation
const apiClient = axios.create(baseConfig);
// Merge for specific requests
const response = await apiClient.request(
axios.mergeConfig(requestConfig, {
method: "get",
url: "/users"
})
);Select appropriate request adapter based on environment and requirements.
/**
* Get appropriate adapter from configuration
* @param adapters - Adapter configuration (string, function, or array)
* @returns Resolved adapter function
*/
axios.getAdapter(adapters: AxiosAdapterConfig | AxiosAdapterConfig[] | undefined): AxiosAdapter;
type AxiosAdapterConfig = AxiosAdapter | AxiosAdapterName;
type AxiosAdapterName = 'fetch' | 'xhr' | 'http' | (string & {});
interface AxiosAdapter {
(config: InternalAxiosRequestConfig): AxiosPromise;
}Usage Examples:
// Get default adapter
const defaultAdapter = axios.getAdapter();
// Specify preferred adapters in order
const adapter = axios.getAdapter(['fetch', 'xhr', 'http']);
// Use specific adapter
const fetchAdapter = axios.getAdapter('fetch');
const xhrAdapter = axios.getAdapter('xhr');
const httpAdapter = axios.getAdapter('http'); // Node.js only
// Use in configuration
const config = {
url: "/api/data",
adapter: axios.getAdapter(['fetch', 'xhr'])
};
// Custom adapter selection logic
function selectAdapter(environment) {
if (environment === 'node') {
return axios.getAdapter('http');
} else if (typeof fetch !== 'undefined') {
return axios.getAdapter('fetch');
} else {
return axios.getAdapter('xhr');
}
}
const customAdapter = selectAdapter(process.env.NODE_ENV);Advanced URL parameter serialization with custom encoders and formats.
interface ParamsSerializerOptions extends SerializerOptions {
/** Custom parameter encoder function */
encode?: ParamEncoder;
/** Custom serialization function */
serialize?: CustomParamsSerializer;
}
interface ParamEncoder {
(value: any, defaultEncoder: (value: any) => any): any;
}
interface CustomParamsSerializer {
(params: Record<string, any>, options?: ParamsSerializerOptions): string;
}Usage Examples:
// Custom parameter serialization
const config = {
url: "/api/search",
params: {
query: "hello world",
filters: {
category: "tech",
date: new Date("2023-01-01")
},
tags: ["javascript", "api"]
},
paramsSerializer: {
serialize: (params, options) => {
const searchParams = new URLSearchParams();
Object.entries(params).forEach(([key, value]) => {
if (Array.isArray(value)) {
value.forEach(item => searchParams.append(`${key}[]`, item));
} else if (typeof value === "object" && value !== null) {
Object.entries(value).forEach(([nestedKey, nestedValue]) => {
searchParams.append(`${key}[${nestedKey}]`, nestedValue);
});
} else {
searchParams.append(key, value);
}
});
return searchParams.toString();
}
}
};
// Results in URL: /api/search?query=hello+world&filters[category]=tech&filters[date]=2023-01-01T00:00:00.000Z&tags[]=javascript&tags[]=api
// Custom encoder for special characters
const customEncoderConfig = {
params: { special: "hello+world" },
paramsSerializer: {
encode: (value, defaultEncoder) => {
if (typeof value === "string") {
return encodeURIComponent(value).replace(/%20/g, "+");
}
return defaultEncoder(value);
}
}
};Transform request and response data automatically.
interface AxiosRequestTransformer {
(this: InternalAxiosRequestConfig, data: any, headers: AxiosRequestHeaders): any;
}
interface AxiosResponseTransformer {
(this: InternalAxiosRequestConfig, data: any, headers: AxiosResponseHeaders, status?: number): any;
}Usage Examples:
// Custom request transformer
const requestTransformer = function(data, headers) {
if (data && typeof data === "object") {
// Convert camelCase to snake_case for API
const transformed = {};
Object.entries(data).forEach(([key, value]) => {
const snakeKey = key.replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`);
transformed[snakeKey] = value;
});
return JSON.stringify(transformed);
}
return data;
};
// Custom response transformer
const responseTransformer = function(data, headers, status) {
if (typeof data === "string") {
try {
data = JSON.parse(data);
} catch (e) {
return data;
}
}
if (data && typeof data === "object") {
// Convert snake_case to camelCase
const transformed = {};
Object.entries(data).forEach(([key, value]) => {
const camelKey = key.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
transformed[camelKey] = value;
});
return transformed;
}
return data;
};
// Use transformers in configuration
const apiClient = axios.create({
transformRequest: [requestTransformer, ...axios.defaults.transformRequest],
transformResponse: [...axios.defaults.transformResponse, responseTransformer]
});
// Multiple transformers
const multiTransformConfig = {
transformRequest: [
// First transformer: handle dates
(data, headers) => {
if (data && typeof data === "object") {
Object.entries(data).forEach(([key, value]) => {
if (value instanceof Date) {
data[key] = value.toISOString();
}
});
}
return data;
},
// Second transformer: JSON stringify
(data, headers) => {
if (data && typeof data === "object") {
headers.setContentType("application/json");
return JSON.stringify(data);
}
return data;
}
]
};Real-world examples of complex data transformation and configuration scenarios.
Usage Examples:
// Complex file upload with progress and validation
const uploadFile = async (file, metadata) => {
const formData = axios.toFormData({
file: file,
metadata: JSON.stringify(metadata),
timestamp: new Date().toISOString()
}, undefined, {
dots: true,
indexes: true,
visitor: function(value, key, path, helpers) {
// Custom handling for different data types
if (value instanceof Date) {
this.append(key, value.toISOString());
return false; // Don't use default handling
}
if (typeof value === 'object' && value.constructor.name === 'File') {
this.append(key, value, value.name);
return false;
}
// Use default handling for other types
return true;
}
});
return axios.post('/api/upload', formData, {
headers: { 'Content-Type': 'multipart/form-data' },
onUploadProgress: (progressEvent) => {
const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total);
console.log(`Upload progress: ${percentCompleted}%`);
},
timeout: 30000, // 30 second timeout for file uploads
maxBodyLength: 50 * 1024 * 1024 // 50MB max file size
});
};
// API client with automatic data transformation
const createAPIClient = (baseURL) => {
const client = axios.create({ baseURL });
// Transform snake_case API responses to camelCase
client.defaults.transformResponse = [
...client.defaults.transformResponse,
(data) => {
if (typeof data === 'object' && data !== null) {
return transformKeys(data, camelCase);
}
return data;
}
];
// Transform camelCase requests to snake_case
client.defaults.transformRequest = [
(data) => {
if (typeof data === 'object' && data !== null) {
return transformKeys(data, snakeCase);
}
return data;
},
...client.defaults.transformRequest
];
return client;
};
// Helper function for key transformation
function transformKeys(obj, transformer) {
if (Array.isArray(obj)) {
return obj.map(item => transformKeys(item, transformer));
}
if (obj && typeof obj === 'object') {
return Object.keys(obj).reduce((result, key) => {
const transformedKey = transformer(key);
result[transformedKey] = transformKeys(obj[key], transformer);
return result;
}, {});
}
return obj;
}
// Modern approach (preferred)
const responses = await Promise.all([
axios.get("/api/users"),
axios.get("/api/posts")
]);
const [usersResponse, postsResponse] = responses;
// Legacy all usage (use Promise.all instead)
axios.all([
axios.get("/api/users"),
axios.get("/api/posts")
]).then(axios.spread((usersRes, postsRes) => {
console.log("Users:", usersRes.data);
console.log("Posts:", postsRes.data);
}));
// Modern approach (preferred)
Promise.all([
axios.get("/api/users"),
axios.get("/api/posts")
]).then(([usersRes, postsRes]) => {
console.log("Users:", usersRes.data);
console.log("Posts:", postsRes.data);
});Complex transformation patterns for real-world applications.
Usage Examples:
// Data normalization pipeline
class DataNormalizer {
static request(data) {
return Object.entries(data || {}).reduce((acc, [key, value]) => {
// Convert dates to ISO strings
if (value instanceof Date) {
acc[key] = value.toISOString();
}
// Convert boolean to string for some APIs
else if (typeof value === "boolean") {
acc[key] = value.toString();
}
// Convert camelCase to snake_case
else {
const snakeKey = key.replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`);
acc[snakeKey] = value;
}
return acc;
}, {});
}
static response(data) {
if (!data || typeof data !== "object") return data;
return Object.entries(data).reduce((acc, [key, value]) => {
// Convert snake_case to camelCase
const camelKey = key.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
// Parse ISO date strings back to Date objects
if (typeof value === "string" && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/.test(value)) {
acc[camelKey] = new Date(value);
} else {
acc[camelKey] = value;
}
return acc;
}, {});
}
}
// Use in axios configuration
const normalizedClient = axios.create({
transformRequest: [
DataNormalizer.request,
...axios.defaults.transformRequest
],
transformResponse: [
...axios.defaults.transformResponse,
DataNormalizer.response
]
});
// Conditional transformation based on content type
const smartTransformer = function(data, headers) {
const contentType = headers.getContentType();
if (contentType === "application/json") {
return JSON.stringify(data);
} else if (contentType === "application/x-www-form-urlencoded") {
return new URLSearchParams(data).toString();
} else if (contentType === "multipart/form-data") {
return axios.toFormData(data);
}
return data;
};