随着前端应用程序的发展,事件源驱动架构(Event Sourcing)变得越来越流行。事件源驱动架构是一种设计模式,它将应用程序状态表示为一系列不可变的事件,这些事件可以被重播以重建应用程序状态。GraphQL 和 MongoDB 是两个流行的技术,它们可以被用来实现事件源驱动架构。
GraphQL 简介
GraphQL 是一个用于构建 API 的查询语言。它由 Facebook 开发,并于 2015 年首次发布。GraphQL 允许客户端定义它们需要从服务器获取的数据,从而减少了网络传输的数据量。GraphQL 的一个重要特点是它的类型系统,它允许客户端和服务器之间的数据类型匹配。
GraphQL 的查询看起来像这样:
query {
user(id: "123") {
name
email
}
}这个查询将从服务器获取一个用户的名称和电子邮件地址。GraphQL 服务器将根据查询返回一个 JSON 对象,其中包含请求的数据。
MongoDB 简介
MongoDB 是一个流行的 NoSQL 数据库。它是一个文档数据库,可以存储任意结构的数据。MongoDB 使用 JSON 格式来存储数据,这使得它非常适合与 GraphQL 配合使用。
MongoDB 的查询看起来像这样:
db.users.find({ name: "Alice" })这个查询将从名为“users”的集合中检索名称为“Alice”的所有文档。MongoDB 还支持更复杂的查询,例如范围查询和聚合查询。
事件源驱动架构
事件源驱动架构是一种将应用程序状态表示为一系列不可变事件的设计模式。每个事件都描述了应用程序状态的变化。事件源驱动架构的一个重要特点是它可以轻松地支持复杂的业务逻辑。
事件源驱动架构的核心是事件存储。事件存储是一个存储所有应用程序事件的数据存储。事件存储只允许追加事件,不允许修改或删除事件。这意味着应用程序状态可以被重建,因为所有状态变化都是由事件描述的。
使用 GraphQL 和 MongoDB 实现事件源驱动架构
使用 GraphQL 和 MongoDB 实现事件源驱动架构需要以下步骤:
- 定义 GraphQL 模式
- 实现 GraphQL 解析器
- 定义事件模式
- 实现事件存储
- 实现事件处理程序
定义 GraphQL 模式
GraphQL 模式定义了客户端可以查询的数据。在事件源驱动架构中,我们需要定义查询和突变。查询用于检索数据,突变用于更新数据。
以下是一个简单的 GraphQL 模式,用于表示用户和他们的订单:
// www.javascriptcn.com code example
type User {
id: ID!
name: String!
email: String!
orders: [Order!]!
}
type Order {
id: ID!
user: User!
items: [String!]!
}
type Query {
user(id: ID!): User
}
type Mutation {
createUser(name: String!, email: String!): User
createOrder(userId: ID!, items: [String!]!): Order
}这个模式定义了一个用户类型和一个订单类型。用户类型有一个名称、一个电子邮件地址和一个订单列表。订单类型有一个用户和一些项目。
实现 GraphQL 解析器
GraphQL 解析器是一个将 GraphQL 查询转换为数据的组件。在事件源驱动架构中,我们需要实现查询和突变的解析器。
以下是一个简单的 GraphQL 解析器,用于实现上面定义的 GraphQL 模式:
// www.javascriptcn.com code example
const resolvers = {
Query: {
user: (parent, args) => {
return db.users.findOne({ _id: args.id });
},
},
Mutation: {
createUser: (parent, args) => {
const user = { name: args.name, email: args.email };
return db.users.insertOne(user).then(result => result.ops[0]);
},
createOrder: (parent, args) => {
const order = { user_id: args.userId, items: args.items };
return db.orders.insertOne(order).then(result => result.ops[0]);
},
},
User: {
orders: (parent) => {
return db.orders.find({ user_id: parent.id }).toArray();
},
},
Order: {
user: (parent) => {
return db.users.findOne({ _id: parent.user_id });
},
},
};这个解析器使用 MongoDB 进行数据存储和检索。它有一个用户查询和两个突变:创建用户和创建订单。它还包括两个字段解析器,用于检索用户的订单和订单的用户。
定义事件模式
事件模式定义了应用程序事件的结构。在事件源驱动架构中,每个事件描述了应用程序状态的变化。事件模式应该包括事件类型、事件数据和事件元数据。
以下是一个简单的事件模式,用于表示用户创建事件:
// www.javascriptcn.com code example
{
"type": "USER_CREATED",
"data": {
"id": "abc123",
"name": "Alice",
"email": "alice@example.com"
},
"metadata": {
"timestamp": 1622010658,
"user_id": "def456"
}
}这个事件描述了一个用户的创建。它包括事件类型、事件数据和事件元数据。事件类型是 USER_CREATED,事件数据包括用户的 ID、名称和电子邮件地址,事件元数据包括时间戳和用户 ID。
实现事件存储
事件存储是一个存储所有应用程序事件的数据存储。在事件源驱动架构中,事件存储只允许追加事件,不允许修改或删除事件。
以下是一个简单的事件存储,用于将事件存储到 MongoDB 中:
const eventStore = {
insert: (event) => {
return db.events.insertOne(event).then(result => result.ops[0]);
},
getAll: () => {
return db.events.find().toArray();
},
};这个事件存储使用 MongoDB 进行数据存储和检索。它有一个插入方法,用于将事件插入到数据库中。它还有一个 getAll 方法,用于检索所有事件。
实现事件处理程序
事件处理程序是一个将事件转换为应用程序状态的组件。在事件源驱动架构中,事件处理程序将事件转换为应用程序状态。
以下是一个简单的事件处理程序,用于处理用户创建事件:
const eventHandlers = {
USER_CREATED: (event) => {
const user = event.data;
return db.users.insertOne(user).then(result => result.ops[0]);
},
};这个事件处理程序处理 USER_CREATED 事件。它从事件中提取用户数据,并将其插入到 MongoDB 中。事件处理程序应该处理所有应用程序事件。
示例代码
以下是一个完整的示例代码,用于使用 GraphQL 和 MongoDB 实现事件源驱动架构:
// www.javascriptcn.com code example
const { ApolloServer, gql } = require("apollo-server");
const { MongoClient, ObjectId } = require("mongodb");
const uri = "mongodb://localhost:27017";
const client = new MongoClient(uri, { useUnifiedTopology: true });
const typeDefs = gql`
type User {
id: ID!
name: String!
email: String!
orders: [Order!]!
}
type Order {
id: ID!
user: User!
items: [String!]!
}
type Query {
user(id: ID!): User
}
type Mutation {
createUser(name: String!, email: String!): User
createOrder(userId: ID!, items: [String!]!): Order
}
`;
const resolvers = {
Query: {
user: (parent, args, context) => {
return context.db
.collection("users")
.findOne({ _id: ObjectId(args.id) });
},
},
Mutation: {
createUser: (parent, args, context) => {
const user = { name: args.name, email: args.email };
const event = {
type: "USER_CREATED",
data: user,
metadata: { timestamp: Date.now(), user_id: "system" },
};
return context.eventStore
.insert(event)
.then(() => context.eventHandlers.USER_CREATED(event))
.then(() =>
context.db.collection("users").findOne({ _id: event.data._id })
);
},
createOrder: (parent, args, context) => {
const order = { user_id: ObjectId(args.userId), items: args.items };
const event = {
type: "ORDER_CREATED",
data: order,
metadata: { timestamp: Date.now(), user_id: "system" },
};
return context.eventStore
.insert(event)
.then(() => context.eventHandlers.ORDER_CREATED(event))
.then(() =>
context.db
.collection("orders")
.findOne({ _id: event.data._id })
.then((order) => ({
...order,
user: context.db
.collection("users")
.findOne({ _id: order.user_id }),
}))
);
},
},
User: {
orders: (parent, args, context) => {
return context.db
.collection("orders")
.find({ user_id: parent._id })
.toArray();
},
},
Order: {
user: (parent, args, context) => {
return context.db
.collection("users")
.findOne({ _id: parent.user_id });
},
},
};
async function start() {
await client.connect();
const db = client.db("test");
const eventStore = {
insert: (event) => {
return db.collection("events").insertOne(event);
},
getAll: () => {
return db.collection("events").find().toArray();
},
};
const eventHandlers = {
USER_CREATED: (event) => {
const user = event.data;
return db.collection("users").insertOne(user);
},
ORDER_CREATED: (event) => {
const order = event.data;
return db.collection("orders").insertOne(order);
},
};
const server = new ApolloServer({
typeDefs,
resolvers,
context: () => ({ db, eventStore, eventHandlers }),
});
const { url } = await server.listen(4000);
console.log(`Server ready at ${url}`);
}
start();这个示例代码使用 Apollo Server、MongoDB 和 Node.js 实现了一个简单的事件源驱动架构。它包括一个 GraphQL 模式、一个 GraphQL 解析器、一个事件模式、一个事件存储和一个事件处理程序。它可以用于创建用户和订单,并检索用户和订单的详细信息。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/67d45069a941bf71348233b8