GraphQL 从入门到精通
Published by powerfulyang on Apr 21, 2023
当您学习 GraphQL 语法时,需要理解它由三个主要构件组成:查询、突变和订阅。每个构件由不同类型的操作组成。我将简要介绍 GraphQL 的语法以及如何定义查询和突变以及和 Nest.JS 一起搭配的介绍。
语法入门
查询语法
GraphQL 查询使用类似 JSON 的语法来定义返回的数据。查询由字段和嵌套字段组成,其中每个字段都可以具有参数和别名。例如:
1{
2 user(id: 123) {
3 id
4 name
5 email
6 }
7}
在 Nest.JS 中使用,您可以通过定义一个对象类型来定义一个查询。对象类型由字段和嵌套类型组成,每个字段都有一个类型和一个解析器函数。例如:
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 关键字。例如:
1mutation {
2 createUser(input: { name: "John", email: "[email protected]" }) {
3 id
4 name
5 email
6 }
7}
在 Nest.JS 中使用,您可以通过定义一个输入类型和一个突变类型来定义一个突变。输入类型由字段和嵌套类型组成,用于指定突变参数。突变类型包含一个名为 mutation 的操作,该操作包含一个名为 createUser 的字段。例如:
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):用于实时获取服务端的数据更新。订阅是一种持续的操作,它可以在服务端的数据更新时自动推送更新给客户端。
1subscription {
2 objectUpdated(id: "123") {
3 field1
4 field2
5 }
6}
在 GraphQL 中,订阅操作用于实时推送数据更新给客户端,例如聊天应用中的新消息通知。订阅操作使用类似于查询和突变的语法,但是在服务端,它们使用 WebSocket 进行实时通信。
在 NestJS 中,您可以使用 @Subscription()
装饰器定义一个订阅操作。下面是一个简单的示例,演示如何使用 NestJS 和 GraphQL 定义一个简单的订阅操作:
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}