随着你的组织的发展,创建多个API服务是很常见的,每个服务都提供自己的功能集。除了这些服务,你还想为你的用户提供不同的客户端应用程序来使用你的产品。最终,你的架构可能看起来像这样。
每个客户端应用程序都有不同的需求。
发生这种情况的原因有很多。随着时间的推移,团队结构可能指导了服务的创建,在当时,让一个团队拥有一个代码库,而不是让一个团队的网络来拥有服务,这更容易。
另一个原因可能是,你的产品中的不同功能有不同的扩展问题。例如,你的分析堆栈可能与你的用户登录堆栈有截然不同的需求,将两者结合起来是没有意义的。
无论原因是什么,这种类型的架构将减缓后端服务团队和前端客户团队的未来发展。客户端应用程序将需要与多个协议对接,使用不同的认证策略,担心哪个API给他们什么类型的数据,并可能为一个页面进行多个API调用来检索数据。
在这种情况下,API网关可以帮助解决这个问题,而不是重构每个API服务或重新构建整个架构--这既费钱又有风险。
什么是GraphQL API网关?
API网关对于微服务来说并不新鲜。我已经看到许多开发者使用它们来为客户端应用程序提供一个单一的接口(和协议),以便从多个来源获得数据。
它们可以通过提供单一的API协议、单一的认证机制来解决之前描述的问题,并确保客户在开发新功能时只需要与一个团队对话。
另一方面,使用GraphQL API网关是一个相对较新的概念,最近已经变得很流行。这是因为GraphQL有一些属性,可以很好地用于API网关。
一个GraphQL API网关可以有一个单一定义的模式和来自许多不同的微服务的源数据,所以客户可以查询字段的组合而不知道数据来自哪里。
有了这个功能,发现如何检索数据就不是一个与谁对话的问题,而是它在GraphQL模式中的位置。
有许多JavaScript包可以帮助开发。有些为实现GraphQL API网关提供了一个抽象层,而有些则可以为你做得更多。
用GraphQL网关进行模式缝合
我们现在需要一个API网关服务,它将负责接收操作并从新的和传统的服务中返回数据。我们可以通过两种不同的方式做到这一点:模式拼接或联盟。
由于时间关系,我们将更仔细地研究模式缝合,但你可以在这篇文章中了解更多关于GraphQL联合的信息。
就使用哪种JavaScript包而言,我们可以用Apollo Server或Mercurius等编写自己的自定义Node.js GraphQL服务器,在那里我们编写代码来解释来自客户端的GraphQL操作,将其发送到下游API,并返回映射到客户端期望的数据。
这种方法是时间密集型的,但根据你的情况,可能是有意义的。它的优点是可以根据你的组织和最佳实践进行专门调整。
使用GraphQL Mesh作为GraphQL API网关
另一方面,像GraphQL Mesh这样的库可以将多个数据源自动拼接成一个单一的GraphQL API。这可以节省开发时间,但是,就像那些为你做很多事情的库一样,你可能需要提供自定义的覆盖。
GraphQL Mesh不仅会作为我们的GraphQL API网关,也会作为我们的数据映射器。它支持不同的数据源,如OpenAPI/Swagger REST APIs、gRPC APIs、数据库、GraphQL(显然)等等。它将采取这些数据源,将它们转化为GraphQL APIs,然后将它们拼接起来。
为了展示这样一个库的力量,我们将创建一个简单的SpaceX飞行日志API。我们的应用程序将记录这些年来我们参加的所有SpaceX发射活动。这里是这个项目的GitHub repo。
我们的应用程序将使用两个数据源:一个告诉我们SpaceX发射情况的公共GraphQL API和一个本地MongoDB数据库。
GraphQL SpaceX API将通过代理提供给我们(所有操作名称都是一样的),但GraphQL Mesh将为我们的MongoDB数据库连接提供新的操作。它将让我们创建用户并标记我们参加的发射。
首先,安装这些库。
npm install @graphql-mesh/cli @graphql-mesh/graphql @graphql-mesh/mongoose graphql mongoose
现在,创建基本的Mongoose模型,描述我们的MongoDB模式。
// ./src/models.js
const { model, Schema } = require("mongoose");
const UserSchema = new Schema(
{
name: {
type: String,
},
},
{
collection: "users",
}
);
const User = model("User", UserSchema);
const LaunchesAttendedSchema = new Schema(
{
spacexLaunchID: {
type: String,
},
userId: { type: "ObjectId", ref: "User" },
},
{
collection: "launches_attended",
}
);
const LaunchesAttended = model("LaunchesAttended", LaunchesAttendedSchema);
module.exports = {
User,
LaunchesAttended,
};
接下来,创建一个GraphQL Mesh配置文件,.meshrc.yaml 。
// .meshrc.yml
sources:
- name: SpaceX
handler:
graphql:
endpoint: https://api.spacex.land/graphql/
method: POST
- name: Mongoose
handler:
mongoose:
connectionString: mongodb://admin:password@localhost:27017/test?authSource=admin&readPreference=primary&appname=MongoDB%20Compass&directConnection=true&ssl=false
models:
- name: User
path: ./src/models.js#User
- name: LaunchesAttended
path: ./src/models.js#LaunchesAttended
用Docker Compose启动MongoDB数据库(这里有docker-compose.yml的例子))。
docker-compose up mongo
就这样了!用Docker Compose为我们的新GraphQL服务器提供服务。
./node_modules/.bin/graphql-mesh serve
这将带你到一个GraphiQL实例,这是一个查询GraphQL服务器的好界面。点击文档的侧边栏,探索我们有哪些可用的选项。你会注意到我们有一种方法可以看到过去的发射。
为了测试我们的新功能,我们可以查询过去的发射,从列表中挑选一个id ,并在MongoDB数据库中为用户创建一个行,以SpaceX发射参考。
首先,创建一个用户。
mutation CreateUser($input: CreateOneUserInput!) {
userCreateOne(record: $input) {
recordId
}
}
现在,获取过去的发射。
query PastLaunches {
launchesPast(limit: 10) {
mission_name
id
launch_date_local
}
}
将一次发射标记为已参加。
mutation LaunchesAttendedCreateOne($input: CreateOneLaunchesAttendedInput!) {
launchesAttendedCreateOne(record: $input) {
recordId
}
}
最后,看到你以前参加的所有发射。
query LaunchesAttended {
launchesAttendedFindMany {
spacexLaunchID
userId
}
}
结论
在很短的时间内(在几个配置文件之后),我们能够建立我们自己的GraphQL API网关,它将SpaceX的GraphQL API和从本地MongoDB数据库生成的GraphQL API缝合在一起,使我们能够创建一个应用程序,记录我们参加的发射。这个用例证明了GraphQL网关对客户的开发经验有多么强大。
如果没有这个网关,客户将需要分别查询两个API。相反,GraphQL Mesh帮助我们快速生成了基本的CRUD操作,我们可以在Mongo数据库上执行,使我们的应用具有用户特定的功能。
总的来说,有很多方法可以使用API网关和大量的库可以选择,以协助你建立一个分布式系统,可以针对性能、安全和多团队组织进行微调。
The postImproving microservice architecture with GraphQL API gatewaysappeared first onLogRocket Blog.