JAVASCRIPT
Normalizing Heterogeneous API Responses with Data Transformation in JavaScript
Transform and map varied API data structures into a consistent, application-specific format using JavaScript for improved data consistency.
/**
* Simulates an API response from a 'users' service with a specific structure.
*/
const userApiResponse = {
status: 'success',
data: {
id: 'usr_101',
username: 'jsmith',
emailAddress: '[email protected]',
creationDate: '2023-01-15T10:30:00Z',
isActiveUser: true,
addressInfo: {
street: '123 Main St',
city: 'Anytown',
zip: '12345'
}
}
};
/**
* Simulates an API response from a 'profiles' service with a different structure.
*/
const profileApiResponse = {
code: 200,
result: {
profileId: 'prof_202',
userIdRef: 'usr_101',
displayName: 'Johnny S.',
contactEmail: '[email protected]',
registrationTimestamp: 1673775600000, // Unix timestamp in ms
status: 'active'
}
};
/**
* Defines the desired standardized data model for a 'User' in our application.
*/
// Desired output structure:
// {
// id: string,
// userId: string, // if different from id
// name: string,
// email: string,
// registeredAt: Date,
// status: 'active' | 'inactive',
// location: { street: string, city: string, postalCode: string }
// }
/**
* Function to transform the user API response into the standardized model.
* @param {object} apiResponse - The raw response from the user API.
* @returns {object|null} The normalized user object or null if data is invalid.
*/
function normalizeUser(apiResponse) {
const userData = apiResponse?.data;
if (!userData) return null;
return {
id: userData.id,
userId: userData.id, // Assuming id and userId are the same for this source
name: userData.username, // Mapping 'username' to 'name'
email: userData.emailAddress,
registeredAt: new Date(userData.creationDate),
status: userData.isActiveUser ? 'active' : 'inactive',
location: {
street: userData.addressInfo?.street || '',
city: userData.addressInfo?.city || '',
postalCode: userData.addressInfo?.zip || '' // Renaming 'zip' to 'postalCode'
}
};
}
/**
* Function to transform the profile API response into the standardized model.
* Note: This might represent a partial user profile that needs to be merged.
* @param {object} apiResponse - The raw response from the profile API.
* @returns {object|null} The normalized profile object or null if data is invalid.
*/
function normalizeProfile(apiResponse) {
const profileData = apiResponse?.result;
if (!profileData) return null;
return {
id: profileData.profileId, // Using profileId as the primary ID for this source
userId: profileData.userIdRef,
name: profileData.displayName, // Mapping 'displayName' to 'name'
email: profileData.contactEmail,
registeredAt: new Date(profileData.registrationTimestamp),
status: profileData.status === 'active' ? 'active' : 'inactive'
};
}
// --- Usage Example ---
const normalizedUser = normalizeUser(userApiResponse);
console.log('Normalized User from User API:');
console.log(JSON.stringify(normalizedUser, null, 2));
const normalizedProfile = normalizeProfile(profileApiResponse);
console.log('
Normalized Profile from Profile API:');
console.log(JSON.stringify(normalizedProfile, null, 2));
// If we need to merge them (common scenario):
const combinedUser = {
...normalizedUser, // Start with user data
...(normalizedProfile && { // Overlay with profile data, ensuring profileData exists
id: normalizedUser.id, // Preserve primary ID from user API, or decide on a merging strategy
name: normalizedProfile.name, // Profile name might be preferred
email: normalizedProfile.email, // Profile email might be more current
// ... other fields from profile that should override or complement
})
};
console.log('
Combined (Normalized) User Data:');
console.log(JSON.stringify(combinedUser, null, 2));
How it works: This JavaScript snippet demonstrates how to normalize data from different API responses into a consistent, application-specific data model. It defines two transformation functions, `normalizeUser` and `normalizeProfile`, each responsible for taking a raw API response with a unique structure and mapping its fields to a predefined standard format. This process involves selecting relevant fields, renaming them (e.g., `emailAddress` to `email`), converting data types (e.g., timestamp to `Date` object), and restructuring nested objects. Data normalization is crucial when integrating with multiple APIs that return heterogeneous data, ensuring uniformity and simplifying data consumption within your application.