假设我们具有以下GraphQL模式:
type Venue implements Node {
country: Country!
id: ID!
name: String!
nid: String!
url: String!
}
此解析器支持:
// @flow
import type {
VenueRecordType,
ResolverType,
} from '../types';
const Venue: ResolverType<VenueRecordType> = {
country: (node, parameters, context) => {
return context.loaders.CountryByIdLoader.load(node.countryId);
},
};
export default Venue;
我希望能够在解析器字段使用父/节点参数值之前对其进行修改。
据我所知阅读文档,实现此目的的唯一方法是实现并包装每个字段,例如
// @flow
import type {
VenueRecordType,
ResolverType,
} from '../types';
const createNodeDecorator = (fieldResolver) => {
const updateNode = (node) => {
// https://media0.giphy.com/media/12NUbkX6p4xOO4/giphy.gif
return node;
};
return (parent, parameteres, context, info) => {
return fieldResolver(updateNode(parent), parameteres, context, info);
};
};
const Venue: ResolverType<VenueRecordType> = {
country: createNodeDecorator((node, parameters, context) => {
return context.loaders.CountryByIdLoader.load(node.countryId);
}),
id: createNodeDecorator((node) => {
return node.id;
}),
name: createNodeDecorator((node) => {
return node.name;
}),
nid: createNodeDecorator((node) => {
return node.nid;
}),
url: createNodeDecorator((node) => {
return node.url;
}),
};
export default Venue;
有更好的方法吗?
理想情况下,我将有一个__load
挂钩在使用解析器之前被调用,例如
const Venue: ResolverType<VenueRecordType> = {
__load: (parent, parameteres, context, info, next) => {
next(parent, parameteres, context, info);
},
country: (node, parameters, context) => {
return context.loaders.CountryByIdLoader.load(node.countryId);
},
};
但据我所知,这不存在。
如何在将父节点传递给解析器之前对其进行修改?
答案 0 :(得分:1)
执行此操作的一种方法是将用于修改节点的逻辑上移。例如,给定查询类型,例如:
type Query {
venues: [Venue!]!
}
我们可以在解析器中执行以下操作:
const resolvers: {
Query: {
venues: async (root, args, context) => {
const venues = await context.loaders.VenueLoader.load()
return venues.map(magic)
}
}
}
这可行,但是这意味着您必须在返回Venue或Venues列表的任何解析器中复制逻辑,这很繁琐且容易出错。如果您已经在使用加载程序,则只需将该逻辑移动到加载程序本身内,并称之为一天。
但是,我们可以更进一步,并使用schema指令。例如,如果您想将相同的逻辑用于不同的类型,或者出于某些奇怪的原因,而只想在某些字段上修改父级,这将很有用。这是一个示例,可让您将指令应用于类型或单个字段:
class MagicDirective extends SchemaDirectiveVisitor {
visitFieldDefinition(field) {
const { resolve = defaultFieldResolver } = field
field.resolve = function (source, args, context, info) {
return resolve.apply(this, [magic(source), args, context, info])
}
}
visitObject(object) {
const fieldMap = object.getFields()
for (const fieldName in fieldMap) {
this.visitFieldDefinition(fieldMap[fieldName])
}
}
}
然后将伪指令作为ApolloServer
的一部分传递到您的schemaDirectives
配置中,并将其包含在您的类型定义中:
directive @magic on FIELD_DEFINITION | OBJECT