Custom Axios Response Data Transformation Pipelines
This guide explains how to configure custom response data
transformation pipelines in the Axios HTTP client. You will learn how to
leverage the transformResponse configuration option and
Axios interceptors to sanitize, normalize, and manipulate incoming
server payloads before they reach your application's business logic.
Using the
transformResponse Property
Axios provides a built-in transformResponse option that
accepts an array of functions. Each function receives the response data
and headers, passes its output to the next function in the pipeline, and
returns the final transformed data.
By default, Axios includes a single transformer that parses JSON strings into JavaScript objects:
axios.defaults.transformResponse = [
function (data) {
return JSON.parse(data);
}
];Building a Multi-Step Transformation Pipeline
When defining custom pipelines, you can chain multiple functions to handle tasks like string decoding, property renaming, or date parsing.
import axios from 'axios';
// 1. Transformer to parse ISO date strings into Date objects
const parseDates = (data) => {
if (typeof data !== 'object' || data === null) return data;
for (const key of Object.keys(data)) {
const value = data[key];
const isoDateFormat = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/;
if (typeof value === 'string' && isoDateFormat.test(value)) {
data[key] = new Date(value);
} else if (typeof value === 'object') {
parseDates(value);
}
}
return data;
};
// 2. Transformer to standardize API response wrappers
const unwrapData = (data) => {
return data && data.payload ? data.payload : data;
};
// Create an Axios instance with the transformation pipeline
const apiClient = axios.create({
baseURL: 'https://api.example.com',
transformResponse: [
// Retain default JSON parsing first
...axios.defaults.transformResponse,
// Add custom transformers sequentially
unwrapData,
parseDates,
],
});
export default apiClient;Configuring Transformations at Different Scopes
You can apply response transformation pipelines at the global level, instance level, or per-request level.
1. Per-Request Configuration
Override or append transformations for specific API calls:
apiClient.get('/users', {
transformResponse: [
...axios.defaults.transformResponse,
(data) => data.map(user => ({ ...user, fullName: `${user.firstName} ${user.lastName}` }))
]
});2. Global Defaults
Apply a pipeline across all Axios calls in your application:
axios.defaults.transformResponse = [
...axios.defaults.transformResponse,
(data) => {
// Custom global transformation
return data;
}
];transformResponse
vs. Response Interceptors
While transformResponse is ideal for synchronous data
manipulation on successful responses, Axios
interceptors provide broader control.
transformResponse: Executes only on raw payload data before the promise resolves. It is strictly meant for data parsing and modification.- Response Interceptors: Access the entire response object (including HTTP status codes, headers, and config) and support asynchronous execution or error handling.
Asynchronous Data Transformations with Interceptors
If your transformation pipeline requires asynchronous operations (such as decrypting data or making secondary lookup requests), use an interceptor instead:
apiClient.interceptors.response.use(async (response) => {
if (response.data?.encrypted) {
response.data = await decryptPayload(response.data.payload);
}
return response;
}, (error) => {
return Promise.reject(error);
});Best Practices
- Preserve Default Parsing: Always include
...axios.defaults.transformResponseat the beginning of your pipeline unless you intend to manually parse raw JSON strings. - Handle Nullish Data: Ensure transformers
defensively check for
null,undefined, or unexpected non-object types to avoid unhandled runtime errors. - Keep Transformers Synchronous: Keep functions in
transformResponsepure and synchronous. Use interceptors wheneverasync/awaitis required.