在现代 Web 应用中,分布式系统已成为必不可少的一部分。分布式系统中的每个服务都有自己的数据源和 API,根据需要向其他服务暴露自己的数据。然而,随着分布式系统规模的增大,开发人员往往面临着多个服务的数据整合问题,这就需要一个能够统一多个服务数据的方案。GraphQL 联邦就是为解决这个问题而生的。
GraphQL 联邦
GraphQL 联邦是一种在分布式系统中使用 GraphQL schema 进行数据整合的方案。它提供了一种方式,使多个 GraphQL API 可以互相协同来查询、组合和聚合数据。GraphQL 联邦将服务的 GraphQL schema 分为两部分:实体和关系。实体代表从服务中获取的数据,关系代表实体之间的联系。将这些 schema 分离开来,可以减少不必要的复杂性并提升可扩展性。
GraphQL 联邦中的服务称为“服务提供者”,它们负责提供自己的 schema 和实体。这些服务通常同时提供一组联邦查询,而联邦查询是将多个 GraphQL schema 组合在一起的查询方式。GraphQL 联邦中的另一个重要组件是“网关”,它是客户端与服务提供者之间的入口点。网关负责将客户端的请求路由到适当的服务提供者,并将响应汇总后返回客户端。
GraphQL 联邦示例
下面是一个简单的示例,演示如何使用 GraphQL 联邦来整合多个服务的数据。假设有两个服务,一个提供有关作者信息的 GraphQL API,另一个提供有关书籍信息的 GraphQL API。我们可以将这些 schema 分为实体和关系:
作者的 GraphQL schema:
type Author @key(fields: "id") { id: ID! name: String! books: [Book] @computedFrom(field:"id") }
书籍的 GraphQL schema:
-- -------------------- ---- ------- ---- ---- ------------ ----- - --- --- ------ ------- ------- ------- - ------ ---- ------ ------------ ----- - --- --- --------- -
在上面的 schema 中,我们标识了作者的 id 作为实体的唯一标识符。然后,我们将 book 中的作者字段与 author 对象关联起来,声明了关系。然后,我们使用 @computedFrom
和 @external
指令来告诉 GraphQL 联邦如何从现有实体中计算复合字段,并将计算指示发布到服务提供者。
接下来,我们可以编写一个联邦查询,用于获取特定书籍的作者和作者的所有书籍:
-- -------------------- ---- ------- ----- ------------------------- ---- - ------------ -------- - ----- ------ - ---- ----- - -- ----- - - - - --- -----
const gateway = new ApolloGateway({ serviceList: [ { name: 'authors', url: 'http://localhost:4001/graphql' }, { name: 'books', url: 'http://localhost:4002/graphql' }, ] });
const server = new ApolloServer({ gateway, subscriptions: false });
server.listen().then(({ url }) => {
console.log(Server ready at ${url}
);
});
-- -------------------- ---- ------- ----------------- --------- -------------------------------------------- ------ - -------- ----------------------------------------- -- -- ------- ------------------------------ ------- ------------- -------------------------------------------------------------------------- ------- -------- ------- --- - ------------------------------------------------------------------------------ -------- ------------------------------------------------------------------------------------------------------------------------