Problem: Compose Nested Adapters

hard
40 min
Chain multiple adapters together to normalize both data shape and error format across APIs.

Problem statement

Your system integrates with two different analytics providers. Both send event data and return responses, but in inconsistent ways:

  • Provider A returns { ok: true, payload: {...} }.

  • Provider B returns { success: true, data: {...} }.

Even worse, each one handles errors differently:

  • Provider A throws regular JavaScript Error objects.

  • Provider B returns an object like { success: false, message: "Invalid key" } instead of throwing.

You need to unify both the response format and the error handling so that all analytics calls look and behave consistently.

Goal

Implement two adapters:

  1. ResponseAdapter: Normalizes different response shapes into { success, result }.

  2. ErrorAdapter: Wraps another adapter and ensures all errors are thrown as standard Error objects.

Then, compose them into a single adapter that exposes:

async sendEvent(event)

Which always:

  • Returns { success, result } on success.

  • Throws an Error on failure, regardless of provider.

Constraints

  • Do not modify the original providers.

  • The ErrorAdapter should wrap the ResponseAdapter.

  • Both adapters must be independent and composable.

  • The final composed adapter should be created explicitly (not via inheritance).

Sample output

The examples below illustrate what the output should look like:

(async () => {
const unifiedA = new ErrorAdapter(new ResponseAdapter(providerA));
const unifiedB = new ErrorAdapter(new ResponseAdapter(providerB));
try {
console.log(await unifiedA.sendEvent({ apiKey: 'abc' }));
console.log(await unifiedB.sendEvent({ apiKey: 'abc' }));
await unifiedA.sendEvent({});
} catch (err) {
console.error('Error:', err.message);
}
})();
/* Expected output:
{ success: true, result: { id: 1, name: 'A' } }
{ success: true, result: { id: 2, name: 'B' } }
Error: Missing API key
*/

Good luck trying the problem! If you’re unsure how to proceed, check the “Solution” tab above.

Problem: Compose Nested Adapters

hard
40 min
Chain multiple adapters together to normalize both data shape and error format across APIs.

Problem statement

Your system integrates with two different analytics providers. Both send event data and return responses, but in inconsistent ways:

  • Provider A returns { ok: true, payload: {...} }.

  • Provider B returns { success: true, data: {...} }.

Even worse, each one handles errors differently:

  • Provider A throws regular JavaScript Error objects.

  • Provider B returns an object like { success: false, message: "Invalid key" } instead of throwing.

You need to unify both the response format and the error handling so that all analytics calls look and behave consistently.

Goal

Implement two adapters:

  1. ResponseAdapter: Normalizes different response shapes into { success, result }.

  2. ErrorAdapter: Wraps another adapter and ensures all errors are thrown as standard Error objects.

Then, compose them into a single adapter that exposes:

async sendEvent(event)

Which always:

  • Returns { success, result } on success.

  • Throws an Error on failure, regardless of provider.

Constraints

  • Do not modify the original providers.

  • The ErrorAdapter should wrap the ResponseAdapter.

  • Both adapters must be independent and composable.

  • The final composed adapter should be created explicitly (not via inheritance).

Sample output

The examples below illustrate what the output should look like:

(async () => {
const unifiedA = new ErrorAdapter(new ResponseAdapter(providerA));
const unifiedB = new ErrorAdapter(new ResponseAdapter(providerB));
try {
console.log(await unifiedA.sendEvent({ apiKey: 'abc' }));
console.log(await unifiedB.sendEvent({ apiKey: 'abc' }));
await unifiedA.sendEvent({});
} catch (err) {
console.error('Error:', err.message);
}
})();
/* Expected output:
{ success: true, result: { id: 1, name: 'A' } }
{ success: true, result: { id: 2, name: 'B' } }
Error: Missing API key
*/

Good luck trying the problem! If you’re unsure how to proceed, check the “Solution” tab above.

Node.js
// Simulated analytics providers
const providerA = {
async send(event) {
if (!event.apiKey) throw new Error('Missing API key');
return { ok: true, payload: { id: 1, name: 'A' } };
}
};
const providerB = {
async send(event) {
if (!event.apiKey) return { success: false, message: 'Missing API key' };
return { success: true, data: { id: 2, name: 'B' } };
}
};
// Your code here
// Example usage
(async () => {
const unifiedA = new ErrorAdapter(new ResponseAdapter(providerA));
const unifiedB = new ErrorAdapter(new ResponseAdapter(providerB));
try {
console.log(await unifiedA.sendEvent({ apiKey: 'abc' }));
console.log(await unifiedB.sendEvent({ apiKey: 'abc' }));
await unifiedA.sendEvent({});
} catch (err) {
console.error('Error:', err.message);
}
})();
/* Expected output:
{ success: true, result: { id: 1, name: 'A' } }
{ success: true, result: { id: 2, name: 'B' } }
Error: Missing API key
*/