Last active
February 4, 2022 13:48
-
-
Save boopathi/2a96def5deecf7db4077594287de5e38 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 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
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)