GraphQL 从入门到精通

当您学习 GraphQL 语法时,需要理解它由三个主要构件组成:查询、突变和订阅。每个构件由不同类型的操作组成。我将简要介绍 GraphQL 的语法以及如何定义查询和突变以及和 Nest.JS 一起搭配的介绍。

语法入门

查询语法

GraphQL 查询使用类似 JSON 的语法来定义返回的数据。查询由字段和嵌套字段组成,其中每个字段都可以具有参数和别名。例如:

graphql
1{
2  user(id: 123) {
3    id
4    name
5    email
6  }
7}

在 Nest.JS 中使用,您可以通过定义一个对象类型来定义一个查询。对象类型由字段和嵌套类型组成,每个字段都有一个类型和一个解析器函数。例如:

ts
1import { ObjectType, Field, Resolver, Query } from '@nestjs/graphql';
2
3@ObjectType()
4class UserType {
5  @Field()
6  id: string;
7
8  @Field()
9  name: string;
10
11  @Field()
12  email: string;
13}
14
15@Resolver(of => UserType)
16export class UserResolver {
17  @Query(returns => UserType)
18  async user(@Args('id') id: string) {
19    // fetch user data from database or other source
20    const user = await fetchUserById(id);
21    return user;
22  }
23}

突变语法

GraphQL 突变用于对服务器进行更改。突变类似于查询,但它们可以带有参数,并且它们必须包含一个 mutation 关键字。例如:

graphql
1mutation {
2  createUser(input: { name: "John", email: "[email protected]" }) {
3    id
4    name
5    email
6  }
7}

在 Nest.JS 中使用,您可以通过定义一个输入类型和一个突变类型来定义一个突变。输入类型由字段和嵌套类型组成,用于指定突变参数。突变类型包含一个名为 mutation 的操作,该操作包含一个名为 createUser 的字段。例如:

ts
1import { InputType, Field } from '@nestjs/graphql';
2
3@InputType()
4class CreateUserInput {
5  @Field()
6  name: string;
7
8  @Field()
9  email: string;
10}
11
12@Resolver()
13export class UserResolver {
14  @Mutation(returns => UserType)
15  async createUser(@Args('input') input: CreateUserInput) {
16    // create user in database or other source
17    const user = await createUser(input);
18    return user;
19  }
20}

订阅

订阅(Subscription):用于实时获取服务端的数据更新。订阅是一种持续的操作,它可以在服务端的数据更新时自动推送更新给客户端。

graphql
1subscription {
2  objectUpdated(id: "123") {
3    field1
4    field2
5  }
6}

在 GraphQL 中,订阅操作用于实时推送数据更新给客户端,例如聊天应用中的新消息通知。订阅操作使用类似于查询和突变的语法,但是在服务端,它们使用 WebSocket 进行实时通信。

在 NestJS 中,您可以使用 @Subscription() 装饰器定义一个订阅操作。下面是一个简单的示例,演示如何使用 NestJS 和 GraphQL 定义一个简单的订阅操作:

ts
1import { PubSub } from 'graphql-subscriptions';
2import { Subscription, Resolver } from '@nestjs/graphql';
3
4const pubSub = new PubSub();
5
6@Resolver()
7export class ChatResolver {
8  @Subscription(returns => String, {
9    filter: (payload, variables) => payload.roomId === variables.roomId,
10  })
11  messageAdded(@Args('roomId') roomId: string) {
12    return pubSub.asyncIterator(`messageAdded_${roomId}`);
13  }
14
15  sendMessage(@Args('roomId') roomId: string, @Args('content') content: string) {
16    const message = { roomId, content };
17    pubSub.publish(`messageAdded_${roomId}`, message);
18  }
19}