Design a Common Data Class to Normalize Different API Responses
Company: Merge
Role: Software Engineer
Category: Software Engineering Fundamentals
Difficulty: medium
Interview Round: Technical Screen
You are given the return values of several API calls that describe the same kind of record but disagree on its shape: field names differ, some values are nested, types and formats vary (an integer ID in one response and a string ID in another, an ISO 8601 date string in one and a Unix timestamp in another), and some fields are present in one response but missing from another. Design a common data class that every one of these responses can be converted into and stored as, and write the code that maps each response into it.
The interviewer supplies the API return values. The exact payloads used in the interview are not reported, so practice with the illustrative pair below, or with any set your interviewer gives you.
Response from API A:
```json
{
"id": 1042,
"first_name": "Ana",
"last_name": "Lee",
"email": "ana.lee@example.com",
"created": "2023-04-01T09:30:00Z",
"status": "active",
"phone": null
}
```
Response from API B:
```json
{
"userId": "u_9f3c",
"name": {"given": "Ana", "family": "Lee"},
"emails": [
{"type": "work", "value": "ana.lee@example.com", "primary": true},
{"type": "personal", "value": "ana@example.org", "primary": false}
],
"createdAt": 1680341400,
"isActive": true,
"timezone": "America/New_York"
}
```
This design portion is short, about 20 to 25 minutes, and it closes with a few brief database and system design questions about the same data (see the follow-up questions).
```hint Shared, optional, specific
Before writing any fields, sort the information into what every response carries, what only some responses carry, and what belongs to a single API. Each group may deserve different treatment in the class.
```
```hint Convert at the edge
Decide where the conversion from each raw shape happens, so that code using the common class never needs to know which API a record came from.
```
### Constraints and Clarifications
- Use any language. The goal is a typed structure that is easy to read and to extend; a heavy framework is not required.
- The common class models the entity that all the responses describe, not the shape of any single API's response.
- Conflicting formats for the same concept (two ID types, two timestamp encodings, a status string versus a boolean) must end up in one representation.
### Clarifying Questions
- Do all responses describe the same entity type, or do some carry related sub-records that should become their own classes?
- Which fields does downstream code actually need, and which of them are required?
- When a response lacks a required field or carries a value in an unexpected format, should the record be rejected or kept with the field empty?
- Can IDs from different APIs collide, that is, can two APIs use the same ID value for different records?
- Must fields that have no place in the common class, or the original raw response, be preserved?
- Will more APIs with new shapes be added later?
### What a Strong Answer Covers
- A typed common class with a clear core: a stable identity that includes the source, required versus optional fields, and explicit "unknown" values
- One representation per concept: timezone-aware timestamps, an enumerated status, lists wherever any source can return several values
- Per-source mapping code that keeps API field names out of the class and out of its callers
- A defined home for source-specific fields and, if needed, the raw payload, so nothing is silently dropped
- Validation and error handling for missing, malformed or unexpected values
- Extensibility: adding another API without changing code that consumes the class
### Follow-up Questions
- How would you store the normalized records in a relational database: a column per field, a JSON column for source-specific fields, or both? Which keys and indexes would you add?
- Two APIs return the same real-world record with conflicting values, for example different email addresses. How would you detect that they are the same record, and which value would you keep?
- One API renames a field or changes its type without notice. How does your design notice, and what keeps the rest of the system working?
- If the records had to be kept current by fetching from each API repeatedly over time, how would you make that ingestion safe to repeat and incremental?
Overview: Design a common data class that can hold API responses describing the same kind of record but differing in field names, nesting, ID types and timestamp formats, plus the code that maps each response into it. It tests data modeling, normalization, handling of missing and extra fields, and how the records would be stored in a database.
Read the full Merge Software Engineer interview experience this question came from