Description
In our resolver map, we have two quite different things:
- Resolvers, which are functions called by graphql-js with useful objects like
info
orcontext
, and they are usually async. - Custom scalars, which are objects, don't have access to
info
orcontext
(or anything request-related) and their functions likeserialize
aren't async.
I wonder if scalars could be more resolver-like?!
Concrete example
Our use case is price rounding. In our case, GraphQL server code doesn't know how to round – it needs to ask a backend API for rounding rules – but it is GraphQL code's responsibility to ensure that values are rounded.
Most prices in our schema are represented by a Money
type that looks like this:
type Money {
amount: MonetaryAmount! # custom scalar
currencyCode: String!
}
We can then do something like this, which works well:
const resolvers = {
Query: {
Money: {
amount: async (money, _, { dataSources: { backendApi } }) =>
round(money.amount, money.currencyCode, backendApi),
},
}
};
async function round(amount, currency, backendApi) {
const roundingInfo = await backendApi.getRoundingInfo(...);
// etc.
}
Some parts of our schema, however, use the scalar directly, skipping the Money
type. For example:
type GoogleEcommerceDataLayerActionField {
id: String!
revenue: MonetaryAmount
tax: MonetaryAmount
}
I'd love to be able to write resolver-like code for it, like this:
// pseudocode!
const resolvers = {
__customScalars: {
MonetaryAmount: async (value, { config, dataSources: { backendApi } }) =>
round(value, config.currencyCode, backendApi),
},
};
Currently, we need to solve this on the specific field level, for example, if there's a field like:
type GoogleEcommercePurchaseDataLayer {
actionField: GoogleEcommerceDataLayerActionField
}
we can hook into actionField
and process the rounding there. But it would be safer and easier if we could solve it at the type level.
What do you think? Has this been considered before? I didn't find much but maybe my search skills have failed me.