将上下文信息绑定到 GraphQL 类型中?

Binding contextual information into a GraphQL type?

假设我有两种 GraphQL 类型:

type Student {
  id: ID!
  name: String!
}

type Classroom {
  id: ID!
  students: [Student!]!
}

type Query {
  classroom(id: ID!): Classroom!
}

然后我可以运行这样的查询:

{
  classroom(id: 1) {
    id
    students {
      id
      name
    }
  }
}

在正确设置解析器的情况下,这将 return 我是与特定教室相关联的学生。

但是,假设我想查找一些与学生在课堂上的表现有关的信息,假设:

averageTestScore: Int!
numAbsences: Int!

我假设我需要一个包装器类型,例如:

type ClassroomStudent {
  averageTestScore: Int!
  numAbsences: Int!
  student: Student!
}

我想知道是否有标准化的方法来做到这一点?此外,我有许多现有查询将 Classroom 直接绑定到 Student,因此引入 ClassroomStudent 将是一个重大的 API 更改。有没有一种方法可以构建我的 API 以允许在不引入向后不兼容的更改的情况下非常有机地引入这些类型的更改?

感谢您的宝贵时间。

中继兼容模式中的一个常见模式是将这样的字段附加到相关边缘:

type StudentConnection {
  pageInfo: PageInfo
  edges: [StudentEdge!]!
}

type StudentEdge {
  cursor: String!
  node: Student!
  averageTestScore: Int!
  numAbsences: Int!
}

type Classroom {
  students: StudentConnection!
  # other fields
}

但是,这仍然与引入您提议的 ClassroomStudent 实际上相同。无论哪种方式,在不破坏 API 的情况下引入这样的更改的技巧是保留(并弃用)前一个字段并以不同的名称引入新字段:

type Classroom {
  students: [Student!]! @deprecated(reason: "Use classroomStudents instead")
  classroomStudents: [ClassroomStudent!]!
  # other fields
}

它可能看起来不漂亮,但它会让您的客户端应用程序在不处理重大更改的情况下进行转换。

另一个可能的选择:

type Student {
  performance(classroom: ID!): StudentPerformance
}

您可以使用必填的课堂参数为学生添加一个字段。如果查询有学生的特定教室,这会强制客户端可能提供相同的教室 ID 两次,但这是一个有效的选项。它还具有允许您直接查询学生而无需获取课堂数据的额外好处:

query {
  students {
    id
    performance(classroom: 1) {
      averageTestScore
      numAbsences
    }
  }
}