Skip to content

Instantly share code, notes, and snippets.

@boopathi
Last active February 4, 2022 13:48
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save boopathi/2a96def5deecf7db4077594287de5e38 to your computer and use it in GitHub Desktop.
Save boopathi/2a96def5deecf7db4077594287de5e38 to your computer and use it in GitHub Desktop.
const productLoader = new DataLoader(getBackendProducts);
const resolvers = {
Query: {
async product(_, { id }, __, info) {
const fields = getFields(info);
const backendFields = getBackendFields(fields, dependencyMap);
const backendResponse = await productLoader.load({ id, fields: backendFields });
const schemaResponse = getSchemaResponse(backendResponse, fields, transformerMap);
return schemaResponse;
}
}
};
const dependencyMap = {
name: ["title"],
price: ["price.currency", "price.amount"],
stock: ["stock_availability"],
};
const transformerMap = {
name: resp => resp.title,
price: resp => `${resp.currency} ${resp.amount}`,
stock: resp => resp.stock_availability,
};
function getFields(info) {
return info
.fieldNodes[0] // TODO: handle all field nodes in other fragments
.selectionSet
.selections
.map(
selection => // TODO: handle fragments
selection.name.value
);
}
function getBackendFields(schemaFields, dependencyMap) {
// Set helps in deduping
const backendFields = new Set(
schemaFields
.map(field => dependencyMap[field])
.reduce((acc, field) => [...acc, ...field], [])
);
return backendFields;
}
async function getBackendProducts(inputs) {
const {ids, mergedFields} = mergeInputs(inputs);
const products = await fetch(`/products?ids=${ids.join(",")}&fields=${mergedFields}`);
return products;
}
function mergeInputs(inputs) {
const ids = [];
const fields = new Set();
for (const input of inputs) {
ids.push(input.ids);
for (const field of input.fields) {
fields.add(field);
}
}
return {
ids,
mergedFields: [...fields].join(",")
};
}
function getSchemaResponse(
backendResponse,
transformerMap,
schemaFields
) {
const schemaResponse = {};
for (const field of schemaFields) {
schemaResponse[field] = transformerMap[field](backendResponse);
}
return schemaResponse;
}
@eelayoubi
Copy link

Hey Boopathi, Why not use field resolving instead of a mapper (getSchemaResponse) that will map each field with the relevant value from the backend?
The power of Graphql relies in its ability to resolve each field in a different way (from a different data source)

@boopathi
Copy link
Author

@eelayoubi Completely true. If you have a single data source for the root field, this will just work. The problem we had was a bit more complicated - We have multiple data sources for a field like product - the data source is picked based on the id. Each data source has a different dependency map and a transformer map. A single resolver for a field would work if there is only one of such things.

I'm looking at further ways to ease this process of writing code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment