GraphQL 中的突变和订阅

在本文中,我们将介绍如何在GraphQL中使用MutationSubscription类型来操作和监视数据的更改,而不仅仅是查询。请随时在官方文档.)中了解更多信息

为了简单起见,我们不会使用任何数据库或HTTPS请求,但知道如何使用模式和resolvers]设置基本的API是必要的。

安装

我们将使用graphql-yoga库来设置我们的服务器,并使用nodemon让它自动重新加载。我们还需要一个像Prepros或[Babel)(https://babeljs.io/))这样的前处理器,这样我们才能使用JAVASCRIPT的最新功能。

1$ npm i graphql-yoga nodemon

样板设置

除了我们的服务器设置之外,我们只有一个空的‘USERS’数组和一个用于返回所有用户的简单模式和解析器。

 1[label server.js]
 2import { GraphQLServer } from 'graphql-yoga'
 3
 4const users = [];
 5
 6const typeDefs = `
 7  type Query {
 8    users: [User!]!
 9  }
10
11  type User {
12    name: String!
13    age: Int!
14  }
15`;
16
17const resolvers = {
18  Query: {
19    user() {
20      return users;
21    }
22  }
23}
24
25const server = new GraphQLServer({ typeDefs, resolvers });
26
27server.start(() => console.log('server running'));

我们需要一个start脚本,它将在我们的输出文件上运行nodemon:

 1[label package.json]
 2{
 3  "name": "graphql-api",
 4  "version": "1.0.0",
 5  "description": "",
 6  "main": "server.js",
 7  "dependencies": {
 8    "graphql-yoga": "^1.16.7"
 9  },
10  "devDependencies": {
11    "nodemon": "^1.19.1"
12  },
13  "scripts": {
14    "start": "nodemon server-dist.js"
15  },
16  "author": "",
17  "license": "ISC"
18}

现在在终端中,您只需运行npm run start即可。

localhost:4000处,我们应该启动[GraphQLname]并运行对Playground](https://github.com/prisma/graphql-playground){name}的查询,返回我们的空数组。

创建突变

我们突变的语法与我们的查询的语法几乎相同。我们只需要声明我们想要什么选项,添加任何参数(如果有的话),并声明在完成时应该返回什么类型。

为了便于组织,通常不是内联添加所有的Out参数,而是将数据分解为其自己的特殊类型,称为)来命名输入,无论解析器以单词Input结尾,因此addUser获得一个AddUserInput`输入。

 1[label server.js]
 2const typeDefs = `
 3  type Mutation {
 4    addUser(data: AddUserInput): User!
 5  }
 6
 7  input AddUserInput {
 8    name: String!, 
 9    age: Int!
10  }
11`;

就像查询一样,我们可以访问args上的参数,并将新用户添加到数组中,然后返回它们。

 1const resolvers = {
 2  Query: {...},
 3  Mutation: {
 4    addUser(parent, args, ctx, info) {
 5      const user = { ...args.data };
 6
 7      users.push(user);
 8      return user;
 9    }
10  }
11}

删除和更新突变

由于语法如此简单,因此几乎可以毫不费力地充实其他CRUD操作。

我们只需按名称搜索用户,就可以知道要删除或更新的项目。

 1[label server.js]
 2const typeDefs = `
 3  type Mutation {
 4    deleteUser(name: String!): User!
 5    updateUser(name: String!, data: UpdateUserInput): User!
 6  }
 7
 8  input UpdateUserInput {
 9    name: String
10    age: Int
11  }
12`
13
14const resolvers = {
15  Query: { ... },
16  Mutation: {
17    deleteUser(parent, args, ctx, info) {
18      // We're just finding the index of the user with a matching name,
19      // checking if it exists, and removing that section of the array.
20      const userIndex = users.findIndex(user => user.name.toLowerCase() === args.name.toLowerCase());
21      if (userIndex === -1) throw new Error('User not found');
22
23      const user = users.splice(userIndex, 1);
24      return user[0];
25    },
26    updateUser(parent, args, ctx, info) {
27      const user = users.find(user => user.name.toLowerCase() === args.who.toLowerCase());
28      if (!user) throw new Error('User not found');
29
30      // This way, only the fields that are passed-in will be changed.
31      if (typeof args.data.name === "string") user.name = args.data.name;
32      if (typeof args.data.age !== "undefined") user.age = args.data.age;
33
34      return user;
35    }
36  }
37}

现在,在localhost:4000处,您可以尝试此突变并再次查询我们的数组。

1mutation {
2  addUser(data: {
3    name: "Alli",
4    age: 48
5  }) {
6    name
7    age
8  }
9}

或在另一个选项卡中:

1mutation {
2  updateUser(name: "Alli", data: {
3    name: "Crusher",
4    age: 27
5  }) {
6    name
7    age
8  }
9}

♪订阅

我们可以使用特殊的Subscription类型来监视数据的任何更改。语法非常类似于查询和突变,只需添加类型Subscription,添加您想要它查看的内容,并返回您想要返回的内容。我们将返回一个定制类型,该类型将向我们发送回已更改的数据,并告诉我们它是创建、删除还是更新操作。

要使用订阅,我们需要使用GraphQL-YOGA中的PubSub,并在进行其他操作之前对其进行初始化。在我们的订阅解析器中,我们将使用一个名为SUBSCRIBE‘的函数,该函数需要返回一个异步事件,我们将其命名为’user。每当我们要将某些内容连接到此订阅时,我们都会使用此事件名称。

 1[label server.js]
 2import { GraphQLServer, PubSub } from 'graphql-yoga';
 3
 4const pubsub = new PubSub();
 5
 6const typeDefs = `
 7type Subscription {
 8  user: UserSubscription!
 9}
10
11type UserSubscription {
12  mutation: String!
13  data: User!
14}
15`
16
17const resolvers = {
18  Query: { ... },
19  Mutation: { ... },
20  Subscription: {
21    user: {
22      subscribe() {
23        return pubsub.asyncIterator('user');
24      }
25    }
26}
27}

我们的订阅本身是设置的,并且在生成的GraphQL文档中可用,但它不知道何时启动或返回什么。回到我们的变化中,我们将添加pubsub.Publish来链接到我们的user事件,并将我们的数据传回。

 1const resolvers = {
 2  Query: { ... },
 3  Mutation: {
 4    addUser(parent, args, ctx, info) {
 5      const user = { ...args.data };
 6
 7      users.push(user);
 8
 9      // We'll just link it to our user event,
10      // and return what type of mutation this is and our new user.
11      pubsub.publish("user", {
12        user: {
13          mutation: "Added",
14          data: user
15        }
16      });
17
18      return user;
19    },
20    deleteUser(parent, args, ctx, info) {
21      const userIndex = users.findIndex(
22        user => user.name.toLowerCase() === args.who.toLowerCase()
23      );
24      if (userIndex === -1) throw new Error("User not found");
25
26      const user = users.splice(userIndex, 1);
27
28      pubsub.publish("user", {
29        user: {
30          mutation: "Deleted",
31          data: user[0]
32        }
33      });
34
35      return user[0];
36    },
37    updateUser(parent, args, ctx, info) {
38      const user = users.find(
39        user => user.name.toLowerCase() === args.who.toLowerCase()
40      );
41      if (!user) throw new Error("User not found");
42
43      if (typeof args.data.name === "string") user.name = args.data.name;
44      if (typeof args.data.age !== "undefined") user.age = args.data.age;
45
46      pubsub.publish("user", {
47        user: {
48          mutation: "Updated",
49          data: user
50        }
51      });
52
53      return user;
54    }
55  },
56  Subscription: { ... }
57};

本地主机:4000上,我们可以打开一个新选项卡并运行以下订阅。你应该看到一个‘监听...’。用一个小小的旋转轮发送信息。在另一个选项卡中,我们现在可以运行我们过去的任何其他突变,我们的订阅将自动返回完成了什么和更改了什么。

1subscription {
2  user {
3    mutation
4    data {
5      name
6      age
7    }
8  }
9}

总结

我希望这对理解如何设置带有突变和订阅的GraphQL API有帮助。如果在设置时有任何问题,您可以随时查看This repo.

Published At
Categories with 技术
Tagged with
comments powered by Disqus