在 GraphQL 模式之间共享结构

Share structure between GraphQL schemas

我有一个 Apollo GraphQL 服务器与 API 返回的响应大致如下结构:

{
  "pagination": {
    "page": 1,
    // more stuff
  },
  sorting: {
    // even more stuff
  },
  data: [ // Actual data ]
}

此结构将在我广泛使用的 API 的几乎所有回复中共享。 data 大多数情况下是一个数组,但也可以是一个对象。

如何以高效的方式编写此代码,这样我就不必在我的架构中的每种数据类型上重复所有这些 paginationsorting 字段?

非常感谢!

定义架构时,您最终会将分页、排序等抽象为单独的类型。所以模式看起来像:

type Bar {
  pagination: Pagination
  sorting: SortingOptions
  data: BarData # I'm an object
}
type Foo {
  pagination: Pagination
  sorting: SortingOptions
  data: [FooData] # I'm an array
}
# more types similar to above
type Pagination {
  page: Int
  # more fields
}
type SortingOptions {
  # more fields
}
type BarData {
  # more fields
}

因此,无论如何,您不必多次列出分页中的每个字段。但是,每种使用分页的类型仍需要将其指定为一个字段——这一要求无可避免。

或者,您可以设置一个类型以用于所有对象。在这种情况下,数据字段将是一个接口(数据),每个接口都有 FooData、BarData 等实现它。在您的数据解析器中,您将定义一个 __resolveType 函数来确定要 return 的数据类型。您可以在查询中传递类型名称变量,然后在 __resolveType 函数中使用该变量来 return 正确的类型。

您可以在 Apollo docs.

中看到一个很好的接口示例

后一种方法的缺点是您必须 return 单个数据对象或它们的数组——您不能混合和匹配——因此您可能必须更改returned 对象的结构以使其工作。

我已经通过创建一个名为 graphql-s2s 的库解决了你的问题。它通过添加对类型继承、通用类型和元数据的支持来增强您的架构。在您的情况下,为您的分页对象创建一个泛型类型可能是一个可行的解决方案。这是一个例子:

const { transpileSchema } = require('graphql-s2s')
const { makeExecutableSchema } = require('graphql-tools')

const schema = `
type Paged<T> {
    data: [T]
    cursor: ID
}
type Node {
    id: ID!
    creationDate: String
}
type Person inherits Node {
    firstname: String!
    middlename: String
    lastname: String!
    age: Int!
    gender: String 
}
type Teacher inherits Person {
    title: String!
}
type Student inherits Person {
    nickname: String!
    questions: Paged<Question>
}
type Question inherits Node {
    name: String!
    text: String!
}
type Query {

  students: Paged<Student>

  teachers: Paged<Teacher>
}
`

const executableSchema = makeExecutableSchema({
  typeDefs: [transpileSchema(schema)],
  resolvers: resolver
})

我已经写了关于这个的更多细节here(在第二部分)。