Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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

eelayoubi commented Feb 24, 2020

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

boopathi commented Feb 24, 2020

@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