GraphQL 是一种用于 API 的查询语言和运行时环境,它能够描述数据的形式和关系,以及如何查询和修改数据。GraphQL 通过定义类型和字段,允许前端开发者按需获取数据,避免了过度获取或缺乏数据的问题。
然而,随着应用程序变得越来越复杂,单个 GraphQL 服务可能无法满足所有数据查询的需求。这时,我们可以使用 GraphQL Federation 实现跨服务的数据查询,将数据从多个服务中组合起来。
GraphQL Federation 简介
GraphQL Federation 是一种将多个 GraphQL 服务组合成一个整体的方法。它基于 Apollo GraphQL,使用了一些标准化的规则和概念,使得多个 GraphQL 服务可以像单个服务一样工作。
在 GraphQL Federation 中,每个服务都是一个独立的 GraphQL 服务,但是它们共享一些公共的类型和字段。这些公共的类型和字段被称为“实体”,表示整个联邦系统中的数据。
每个服务都可以定义自己的实体类型,同时也可以引用其他服务中的实体类型。这样,当一个查询跨越多个服务时,Federation 会自动将这些实体类型组合起来,并返回一个完整的查询结果。
在 GraphQL Federation 中使用实体类型
在 GraphQL Federation 中,我们需要定义实体类型,并在每个服务中使用它们。实体类型通常包含一个唯一的 ID 和一些共享的字段。
例如,我们可以定义一个 User
实体类型,它包含 id
和 name
两个字段:
type User @key(fields: "id") { id: ID! name: String! }
在每个服务中,我们可以使用 extend
关键字扩展这个类型,并添加一些服务特定的字段:
extend type User @key(fields: "id") { id: ID! @external name: String! @external email: String! }
这样,User
实体类型就成为了一个公共类型,可以在所有服务中使用。同时,每个服务也可以添加自己的字段,以满足自己的需求。
在 GraphQL Federation 中定义查询
在 GraphQL Federation 中,我们可以定义一个联邦查询,它可以跨越多个服务进行查询。联邦查询使用 @provides
和 @requires
指令来描述每个服务提供的数据和需要的数据。
例如,假设我们有两个服务,一个是用户服务,一个是订单服务。我们可以定义一个联邦查询,查询某个用户的订单列表:
// javascriptcn.com 代码示例 type Query { user(id: ID!): User @provides(fields: "id name") } extend type User @key(fields: "id") { id: ID! @external name: String! @external orders: [Order] @requires(fields: "id") } type Order { id: ID! status: String! }
在这个联邦查询中,我们首先查询用户服务,获取用户的 id
和 name
字段。然后,我们将这些字段传递给订单服务,获取该用户的订单列表。
需要注意的是,@provides
指令用于描述服务提供的数据,@requires
指令用于描述服务需要的数据。这样,Federation 就可以自动将这些服务组合起来,并返回一个完整的查询结果。
在 GraphQL Federation 中使用 Apollo Gateway
在 GraphQL Federation 中,我们需要使用 Apollo Gateway 来组合多个 GraphQL 服务。Apollo Gateway 是一个用于联邦查询的中间件,可以将多个 GraphQL 服务组合成一个整体。
使用 Apollo Gateway 非常简单,我们只需要在 index.js
文件中定义一个 ApolloServer,然后将多个 GraphQL 服务传递给它即可:
// javascriptcn.com 代码示例 const { ApolloServer } = require('apollo-server') const { ApolloGateway } = require('@apollo/gateway') const gateway = new ApolloGateway({ serviceList: [ { name: 'users', url: 'http://localhost:4001/graphql' }, { name: 'orders', url: 'http://localhost:4002/graphql' }, ], }) const server = new ApolloServer({ gateway, subscriptions: false, }) server.listen().then(({ url }) => { console.log(`🚀 Server ready at ${url}`) })
在这个例子中,我们将两个 GraphQL 服务分别命名为 users
和 orders
,然后将它们传递给 Apollo Gateway。这样,我们就可以使用 Apollo Gateway 进行联邦查询了。
示例代码
以下是一个完整的示例代码,它使用 GraphQL Federation 实现跨服务的数据查询:
// javascriptcn.com 代码示例 # User service type User @key(fields: "id") { id: ID! name: String! } extend type User @key(fields: "id") { id: ID! @external name: String! @external email: String! } type Query { user(id: ID!): User @provides(fields: "id name") } # Order service type Order @key(fields: "id") { id: ID! status: String! } extend type User @key(fields: "id") { id: ID! @external name: String! @external orders: [Order] @requires(fields: "id") } type Query { orders(userId: ID!): [Order] @provides(fields: "id") } # Apollo Gateway const { ApolloServer } = require('apollo-server') const { ApolloGateway } = require('@apollo/gateway') const gateway = new ApolloGateway({ serviceList: [ { name: 'users', url: 'http://localhost:4001/graphql' }, { name: 'orders', url: 'http://localhost:4002/graphql' }, ], }) const server = new ApolloServer({ gateway, subscriptions: false, }) server.listen().then(({ url }) => { console.log(`🚀 Server ready at ${url}`) })
总结
GraphQL Federation 是一种将多个 GraphQL 服务组合成一个整体的方法。它通过定义实体类型和联邦查询,使得多个服务可以像单个服务一样工作。
在使用 GraphQL Federation 时,我们需要定义实体类型,并在每个服务中使用它们。同时,我们也需要定义联邦查询,并使用 Apollo Gateway 将多个服务组合起来。
相比于传统的 REST API,GraphQL Federation 更加灵活和可扩展。它可以将多个服务组合起来,让前端开发者按需获取数据,提高了应用程序的性能和可维护性。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/6569e645d2f5e1655d26495d