JAVASCRIPT

Mapping Complex API Responses to Simple Data Models

Learn to transform verbose or inconsistently structured API response data into a clean, consistent, and easy-to-use local data model in JavaScript for better application maintainability.

/**
 * Represents a simplified user profile for the application.
 * @typedef {object} UserProfile
 * @property {string} id - Unique user identifier.
 * @property {string} fullName - User's first and last name combined.
 * @property {string} emailAddress - User's email.
 * @property {string} avatarUrl - URL to the user's avatar image.
 * @property {boolean} isActive - Whether the user account is active.
 * @property {string} registrationDate - Date of user registration in ISO format.
 */

/**
 * Transforms a complex API user response into a simplified UserProfile object.
 * This function handles various naming conventions, nested objects, and data types.
 * @param {object} apiUserData - The raw user data object from the API.
 * @returns {UserProfile|null} A simplified UserProfile object, or null if essential data is missing.
 */
function transformApiUserToUserProfile(apiUserData) {
  if (!apiUserData || !apiUserData.userId || !apiUserData.contactInfo?.email) {
    console.warn('Incomplete API user data provided for transformation.', apiUserData);
    return null;
  }

  const firstName = apiUserData.personalDetails?.firstName || apiUserData.fName || '';
  const lastName = apiUserData.personalDetails?.lastName || apiUserData.lName || '';
  const fullName = `${firstName} ${lastName}`.trim();

  return {
    id: String(apiUserData.userId), // Ensure ID is a string
    fullName: fullName || 'N/A',
    emailAddress: apiUserData.contactInfo.email,
    avatarUrl: apiUserData.profile?.imageLink || 'https://example.com/default-avatar.png',
    isActive: apiUserData.accountStatus === 'active', // Map string status to boolean
    registrationDate: new Date(apiUserData.createdAt || apiUserData.registeredAt).toISOString(),
  };
}

// Example API Response Structure:
// const complexApiUserData = {
//   userId: 12345,
//   personalDetails: {
//     firstName: 'John',
//     lastName: 'Doe',
//     dateOfBirth: '1990-05-15'
//   },
//   contactInfo: {
//     email: '[email protected]',
//     phone: '+1-555-123-4567'
//   },
//   profile: {
//     imageLink: 'https://example.com/avatars/john.jpg',
//     bio: 'Software Developer'
//   },
//   accountStatus: 'active',
//   createdAt: '2020-01-01T10:00:00Z',
//   preferences: {
//     theme: 'dark'
//   }
// };

// Another example with slightly different fields:
// const alternativeApiUserData = {
//   userId: 'UUID-67890',
//   fName: 'Jane',
//   lName: 'Smith',
//   contactInfo: {
//     email: '[email protected]',
//     phone: '+1-555-987-6543'
//   },
//   profile: { /* no imageLink */ },
//   accountStatus: 'inactive',
//   registeredAt: '2021-03-10T14:30:00Z'
// };

// const transformedUser = transformApiUserToUserProfile(complexApiUserData);
// console.log('Transformed User 1:', transformedUser);
/* Expected output:
{
  id: '12345',
  fullName: 'John Doe',
  emailAddress: '[email protected]',
  avatarUrl: 'https://example.com/avatars/john.jpg',
  isActive: true,
  registrationDate: '2020-01-01T10:00:00.000Z'
}
*/

// const transformedUser2 = transformApiUserToUserProfile(alternativeApiUserData);
// console.log('Transformed User 2:', transformedUser2);
/* Expected output:
{
  id: 'UUID-67890',
  fullName: 'Jane Smith',
  emailAddress: '[email protected]',
  avatarUrl: 'https://example.com/default-avatar.png',
  isActive: false,
  registrationDate: '2021-03-10T14:30:00.000Z'
}
*/

// const incompleteUser = transformApiUserToUserProfile({ userId: 123 }); // Returns null
// console.log('Incomplete User:', incompleteUser);
How it works: This JavaScript snippet demonstrates a common practice in API integration: transforming raw, potentially complex or inconsistent API response data into a clean, predefined local data model. The `transformApiUserToUserProfile` function specifically maps various fields from an `apiUserData` object (handling nested properties, different naming conventions, and default values) into a simpler `UserProfile` structure. This approach centralizes data normalization, making application code that consumes this data more readable, maintainable, and resilient to changes in the external API's structure.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs