Using facebook's reference library, I found a way to hack generic types like this:
type PagedResource<Query, Item> = (pagedQuery: PagedQuery<Query>) => PagedResponse<Item>
interface PagedQuery<Query> {
query: Query;
take: number;
skip: number;
}
interface PagedResponse<Item> {
items: Array<Item>;
total: number;
}
function pagedResource({type, resolve, args}) {
return {
type: pagedType(type),
args: Object.assign(args, {
page: { type: new GraphQLNonNull(pageQueryType()) }
}),
resolve
};
function pageQueryType() {
return new GraphQLInputObjectType({
name: 'PageQuery',
fields: {
skip: { type: new GraphQLNonNull(GraphQLInt) },
take: { type: new GraphQLNonNull(GraphQLInt) }
}
});
}
function pagedType(type) {
return new GraphQLObjectType({
name: 'Paged' + type.toString(),
fields: {
items: { type: new GraphQLNonNull(new GraphQLList(type)) },
total: { type: new GraphQLNonNull(GraphQLInt) }
}
});
}
}
But I like how with Apollo Server I can declaratively create the schema. So question is, how do you guys go about creating generic-like types with the schema language?
答案 0 :(得分:2)
您可以创建接口或联合以获得类似的结果。我认为this article能够很好地解释如何正确实现接口和联合。您的架构看起来像这样:
type Query {
pagedQuery(page: PageInput!): PagedResult
}
input PageInput {
skip: Int!
take: Int!
}
type PagedResult {
items: [Pageable!]!
total: Int
}
# Regular type definitions for Bar, Foo, Baz types...
union Pageable = Bar | Foo | Baz
您还需要为union定义resolveType方法。使用graphql-tools
,这是通过解析器完成的:
const resolvers = {
Query: { ... },
Pageable {
__resolveType: (obj) => {
// resolve logic here, needs to return a string specifying type
// i.e. if (obj.__typename == 'Foo') return 'Foo'
}
}
}
__resolveType
将业务对象作为第一个参数进行解析(通常是您给GraphQL解析的原始数据库结果)。你需要在这里应用一些逻辑来计算出我们正在处理的所有不同的Pageable类型。对于大多数ORM,您只需向正在使用的模型实例添加某种typename
字段,然后让resolveType
返回该字段。
编辑正如您所指出的,此方法的缺点是项目中返回的类型对客户端不再透明 - 客户端必须知道返回的类型和在items
之类的内联片段中指定... on Foo
的字段。当然,您的客户仍然需要了解返回的类型,否则他们将不知道要请求的字段。
我想在以声明方式生成模式时,无法以您想要的方式创建泛型。要使您的架构以与当前相同的方式工作,您必须咬住子弹并在定义PagedFoo
时定义Foo
,在定义PagedBar
时定义Bar
等等。
我能想到的唯一另一种选择是将这两种方法结合起来。以编程方式创建“基础”模式。您只需要使用pagedResource
函数在根查询下定义分页查询。然后,您可以使用printSchema
中的graphql/utilities
将其转换为可与其他类型定义连接的字符串。在类型定义中,您可以使用extend
关键字构建已在基本模式中声明的任何类型,如下所示:
extend Query {
nonPaginatedQuery: Result
}
如果你走这条路线,你可以跳过将resolve
函数传递给pagedResource
,或者在编程定义的类型上定义任何解析器,并且只使用通常传递给{{的解析器对象1}}。