我们正在开发一个非常复杂的GraphQL架构,其中我们有几个属于各种微服务的对象类型,其中每个对象类型都有一个我们可以查询的自然API端点。因此,如果可以直接为某些对象类型定义特定的解析器,这样做会很方便:
const typeDefs = gql`
type Query {
getBook(bookId: ID!): BookPayload
}
type BookPayload {
book: Book
userErrors: UserError
}
type Book {
id: ID!
title: String
author: String
}
`;
const resolvers = {
Query: {
getBook: (parent, args, context, info) => {
return {
book: { id: args.bookId }
}
},
Book: (parent) => { // this object type level resolver doesn't seem to work
return {
id: parent.id,
...fetchBookMetadata(parent.id)
};
}
};
我理解这是一个微不足道的例子,可能看起来有点过度设计,但是当架构开始变得非常复杂并且遍布数百个交叉引用时,它确实更有意义(至少对我们而言)。现在有解决这个问题的好方法吗?
是的,您应该可以使用指令执行此操作或非常类似的操作,请查看:
我将在这里发布引文和本文中的示例。
假设您已经定义了与REST资源对应的对象类型,并且您希望避免为每个字段实现解析器函数
const typeDefs = `
directive @rest(url: String) on FIELD_DEFINITION
type Query {
people: [Person] @rest(url: "/api/v1/people")
}`;
class RestDirective extends SchemaDirectiveVisitor {
public visitFieldDefinition(field) {
const { url } = this.args;
field.resolve = () => fetch(url);
}
}
根据规范,GraphQL执行引擎在选择集上运行,选择集分解为单个字段。将检查每个字段的值或现有解析程序。
看起来如果你定义一个如上所述的指令,你就不会改变这个基本行为,但你会在进一步解决之前拦截并添加一个额外的自定义步骤来执行。
也许类似的东西可能与自定义标量类似,但这不适用于架构设计。