使用GraphQL创建API教程

概述

GraphQL 是一种用于 API 的查询语言和运行时环境。它被设计为一种替代 REST API 的解决方案,提供了更高效、强大、灵活的数据查询和操纵方式。具有如下特点:

  • 声明性数据获取: GraphQL 允许客户端明确声明需要从服务器获取哪些数据,以及需要获取的数据的结构。这种声明性的数据获取方式可以减少不必要的数据传输,提高效率。
  • 单一端点: 与 REST 不同,GraphQL 通常只使用一个端点来处理所有的请求。客户端可以根据自己的需求精确地指定所需的数据,避免了在 REST 中可能出现的过度获取或获取不足的问题。
  • 精确返回: GraphQL 返回的结果与客户端的请求一一对应,不多也不少。这样客户端就可以获得其需要的精确数据,而无需多次请求不同的端点或者在本地进行多次数据处理。
  • 自动文档生成: 由于 GraphQL 查询语言的自描述性,可以轻松地生成文档。开发人员可以查看完整的 API 文档,包括可用查询、变更和类型等信息。
  • 多平台兼容: GraphQL 不限定于特定的后端语言或前端框架,可以与各种技术栈和平台一起使用。
  • 批量查询: GraphQL 支持一次发送多个请求,并在一个请求中获取多个资源,从而减少网络请求的数量。

创建API的通用步骤

1.安装相关依赖

安装四个依赖包

perl 复制代码
"graphql": "^16.6.0",
"apollo-server-express": "^3.10.3",
"@nestjs/apollo": "^10.1.3",
"@nestjs/graphql": "^10.1.3"

graphql (^16.6.0):

作用: 这是 GraphQL 的 JavaScript/TypeScript 实现。它包含了用于定义和执行 GraphQL 操作的核心库。你可以使用它在 Node.js 服务器上构建 GraphQL 服务,或者在客户端发起 GraphQL 查询。

apollo-server-express (^3.10.3):

作用: 这是 Apollo Server 的 Express 版本。Apollo Server 是一个用于构建 GraphQL 服务的开源工具。apollo-server-express 可以与 Express 框架集成,提供了在 Express 应用中轻松创建 GraphQL 服务的能力。它还支持 GraphQL 的特性,如实时查询(subscriptions)等。

@nestjs/apollo (^10.1.3):

作用: 这是 NestJS 的官方 GraphQL 模块。NestJS 是一个基于 TypeScript 的服务器端框架,@nestjs/apollo 模块扩展了 NestJS,使其能够更容易地与 Apollo Server 集成。它提供了一些用于定义 GraphQL 模块、服务和控制器的装饰器,简化了 GraphQL 在 NestJS 应用中的使用。

@nestjs/graphql (^10.1.3):

作用: 这也是 NestJS 的官方 GraphQL 模块。与 @nestjs/apollo 不同,@nestjs/graphql 提供了一种不依赖于 Apollo Server 的纯粹 NestJS 的 GraphQL 模块。它允许你使用 NestJS 的方式来定义 GraphQL 模块、服务和控制器,而不依赖于特定的 GraphQL 服务器实现。

这四个包通常一起使用,用于在 NestJS 应用中构建和处理 GraphQL 服务。可以选择使用 Apollo Server 或者纯粹的 NestJS GraphQL 模块,这取决于你的项目需求和喜好。graphql 是核心的 GraphQL 实现,而 apollo-server-express、@nestjs/apollo、@nestjs/graphql 是用于在 Node.js 应用中构建 GraphQL 服务的框架和库。

2.注册GraphQLModule

app.module.ts中注册GraphQLModule 。

php 复制代码
GraphQLModule.forRoot({
  driver: ApolloDriver,
  autoSchemaFile: true,
}),

在Nest.js中使用GraphQLModule.forRoot方法来配置和启用GraphQL服务时,你可以传递一个包含配置选项的对象。在你提供的代码片段中,GraphQLModule.forRoot的配置选项如下:

driver: ApolloDriver: 这个选项指定了使用的GraphQL驱动程序。在这个配置中,ApolloDriver表示使用Apollo Server作为GraphQL服务的驱动程序。Apollo Server是一个流行的GraphQL服务器实现,它提供了许多功能,例如性能追踪、错误处理、数据缓存等。用于构建和处理GraphQL API,通过选择适当的驱动程序,你可以根据你的需求使用不同的GraphQL实现。

autoSchemaFile: true: 这个选项用于自动生成GraphQL模式文件。GraphQL模式文件(通常是.graphql或.gql文件)定义了可用的GraphQL查询、类型和操作。当设置为true时,Nest.js会在应用程序启动时根据你的Resolver和Type定义自动生成这个模式文件。这个模式文件在开发过程中非常有用,因为它可以用于文档生成、客户端代码生成等目的。

总之,通过这个配置,你告诉Nest.js使用Apollo Server作为GraphQL的驱动程序,并且启用了自动生成GraphQL模式文件的功能。这样,你就可以在应用程序中方便地定义和处理GraphQL查询,并且可以使用自动生成的模式文件进行相关的开发和文档工作。

3.创建Resolver

在GraphQL中,Resolver(解析器)是用来定义GraphQL查询的执行逻辑的函数。每个字段在GraphQL查询中都可以有一个相应的解析器。当客户端发起一个GraphQL查询时,服务器端的解析器就会被调用,用来处理查询并返回相应的数据。

定义输入输出类型

kotlin 复制代码
import { Field, InputType } from '@nestjs/graphql';

@InputType()
export class UserInput {
  @Field()
  name: string;
  @Field()
  desc: string;
}

上述代码中:

@InputType() 装饰器:@InputType() 是一个装饰器,用于将一个普通的 TypeScript 类标记为 GraphQL 的输入类型。输入类型通常用于表示客户端向服务器发送的数据的结构,例如用于创建或更新某个资源的请求数据。

@Field() 装饰器:@Field() 也是一个装饰器,它用于将一个类的属性标记为 GraphQL 的字段。在输入类型中,@Field() 装饰器用于定义客户端可以传递的字段。

定义 UserInput 类中的属性 name 和 desc 为 GraphQL 的字段。这意味着在 GraphQL 查询中,客户端可以使用 name 和 desc 作为字段名,传递相应的值。在这个例子中,name 和 desc 都被定义为字符串类型的字段。

定义输出类型:

kotlin 复制代码
import { Field, ObjectType } from '@nestjs/graphql';

@ObjectType()
export class UserType {
  @Field()
  id?: string;
  @Field()
  name?: string;
  @Field()
  desc: string;
  @Field()
  account: string;
}

@ObjectType() 装饰器将 UserType 类标记为 GraphQL 的对象类型。这意味着它可以被用作 GraphQL 查询的返回类型

@Field() 装饰器用于定义 UserType 类中的属性 id、name、desc 和 account 为 GraphQL 的字段。这意味着在 GraphQL 查询中,客户端可以请求这些字段的值。在这个例子中,id 和 name 字段被定义为可选的字符串类型,而 desc 和 account 字段被定义为必需的字符串类型。

接下来编写具体的resolver代码

typescript 复制代码
import { Args, Mutation, Query, Resolver } from '@nestjs/graphql';
import { UserService } from './user.service';
import { UserInput } from './dto/user-input.type';
import { UserType } from './dto/user.type';

@Resolver()
export class UserResolver {
  constructor(private readonly userService: UserService) {}
  @Mutation(() => Boolean, { description: '新增用户' })
  async create(@Args('params') params: UserInput): Promise<boolean> {
    return await this.userService.create(params);
  }
  @Query(() => UserType, { description: '使用 ID 查询用户' })
  async find(@Args('id') id: string): Promise<UserType> {
    return await this.userService.find(id);
  }
}

下列代码中:

@Resolver(): 是一个装饰器,它将类标记为一个GraphQL Resolver。Resolver是用于处理GraphQL查询和操作的类,其中定义了相应的查询字段和变更操作。

export class UserResolver { }: 这是一个GraphQL Resolver的类定义。该类负责处理与用户相关的GraphQL查询和变更请求。

constructor(private readonly userService: UserService) { }: 在UserResolver类的构造函数中,注入了一个UserService的实例。 这是依赖注入(Dependency Injection)的一种方式,它允许你在Resolver中使用UserService的方法,处理具体的业务逻辑。

@Mutation(() => Boolean, { description: '新增用户' }): 这是一个Mutation字段的定义。Mutation字段用于处理对数据进行变更的请求,这里定义了一个名为create的Mutation字段。它接受一个参数params,类型为UserInput,表示创建用户时需要提供的输入数据。返回类型为Boolean,表示操作成功或失败。{ description: '新增用户' }是对这个Mutation字段的描述。

async create(@Args('params') params: UserInput): Promise<boolean> { }: 这是create Mutation字段的具体处理函数。它使用@Args装饰器来获取传入的参数params,类型为UserInput,并调用UserService的create方法来创建用户。函数返回一个Promise,表示操作是否成功。

@Query(() => UserType, { description: '使用 ID 查询用户' }): 这是一个Query字段的定义。Query字段用于处理对数据的查询请求,这里定义了一个名为find的Query字段。它接受一个参数id,表示要查询的用户ID。返回类型为UserType,表示查询结果的数据类型。{ description: '使用 ID 查询用户' }是对这个Query字段的描述。

async find(@Args('id') id: string): Promise { }: 这是find Query字段的具体处理函数。它使用@Args装饰器来获取传入的参数id,类型为string,并调用UserService的find方法来根据用户ID查询用户信息。函数返回一个Promise,表示查询结果。

总的来说,这段代码定义了一个GraphQL Resolver,包含了两个字段:一个Mutation字段用于创建用户,一个Query字段用于根据用户ID查询用户信息。Resolver中的具体操作通过依赖注入的方式,使用UserService中的方法来处理业务逻辑。

创建好resolver以后一定记得注册下

在 user.module.ts 里的 providers 里需要引入下 user.resolver.ts

python 复制代码
import { Module, ConsoleLogger } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { UserService } from './user.service';
import { User } from './models/user.entity';
import { UserResolver } from './user.resolver';

@Module({
  imports: [TypeOrmModule.forFeature([User])],
  providers: [ConsoleLogger, UserService, UserResolver],
  exports: [UserService],
})
export class UserModule {}

在Nest.js中,Resolver是用来处理GraphQL请求的函数,它包含了处理请求的逻辑。当你创建了一个新的Resolver后,你需要将它注册到Nest.js应用程序的模块中,以便系统知道在收到相应的GraphQL请求时应该使用哪个Resolver来处理。

假设你在user.resolver.ts文件中创建了一个UserResolver,它包含了处理用户相关操作的逻辑,例如查询用户信息、创建用户等。在Nest.js中,你需要将这个UserResolver类添加到你的user.module.ts文件中的providers数组里,以便将它注册到Nest.js的依赖注入系统中。当GraphQL请求到达时,Nest.js会使用这个注册的UserResolver来处理请求。

ini 复制代码
providers: [ConsoleLogger, UserService, UserResolver],

UserResolver被添加到UserModule模块的providers数组中。这样一来,当GraphQL请求中包含与UserResolver相关的查询时,Nest.js就会使用UserResolver中定义的逻辑来处理这些查询请求。

通过这种方式,确保了在GraphQL请求中使用UserResolver时,Nest.js知道应该使用哪个Resolver来处理请求,并且系统会按照你在UserResolver中定义的逻辑来执行相应的操作。

4.工具调试

随后通过graphql访问,就会进入一个可视化界面

用户修改

执行用户修改,这段代码是一个 GraphQL Mutation 操作的定义,用于在服务器端执行更新操作

php 复制代码
mutation update($id: String!,$params: UserInput!){
  update(id: $id, params: $params)
}

mutation update($id: String!, $params: UserInput!): 这行代码定义了一个 Mutation 操作,命名为 update。mutation 关键字表示这是一个用于更新或修改数据的 GraphQL 操作。

$id: String!: 这是一个输入参数,表示要更新的对象的唯一标识符。String! 表示这是一个非空的字符串类型。

$params: UserInput!: 这是另一个输入参数,表示要更新的对象的新属性。UserInput! 表示这是一个非空的自定义输入类型(通常是一个包含多个字段的对象)。

update(id: $id, params: $params): 这是 Mutation 操作的主体,调用了名为 update 的实际处理函数(或者后端的 resolver 函数)。在这里,id 和 params 是从 Mutation 操作的输入参数中传递进来的。

$id 和 $params: 这是通过 Mutation 操作的参数传递给后端的实际值。 <math xmlns="http://www.w3.org/1998/Math/MathML"> i d 对应了前面定义的 id 对应了前面定义的 </math>id对应了前面定义的id 输入参数, <math xmlns="http://www.w3.org/1998/Math/MathML"> p a r a m s 对应了 params 对应了 </math>params对应了params 输入参数。

在实际使用时,你需要提供一个对应于这个 Mutation 操作的 resolver 函数,这个函数会接收到传递进来的 id 和 params 参数,并执行相应的数据更新逻辑。这种结构的 GraphQL Mutation 操作允许客户端以一种清晰和结构化的方式指定数据更新的要求。

请求参数

json 复制代码
{
  "id": "22820297-e288-42ba-aadf-3a4062c5c3cb",
  "params": {
    "desc": "超级管理员",
    "name": "麦子0"
  }
}

执行完成之后,可以看到数据确实发生变化

删除用户

现在将数据库服务器中这一条数据删除,

这段代码是一个 GraphQL Resolver 中的 Mutation 操作的定义,用于删除用户

less 复制代码
  @Mutation(() => Boolean, { description: '删除用户' })
  async del(@Args('id') id: string): Promise<boolean> {
    return await this.userService.del(id);
  }

@Mutation(() => Boolean, { description: '删除用户' }): 这是一个装饰器,用于定义 Mutation 操作。@Mutation 表示这是一个 Mutation 操作,() => Boolean 表示该 Mutation 的返回类型为布尔值,即表示操作的成功或失败。{ description: '删除用户' } 是对这个 Mutation 操作的描述。

async del(@Args('id') id: string): Promise<boolean>: 这是 Mutation 操作的实际方法,被命名为 del。它是一个异步方法,接受一个参数 id,表示要删除的用户的唯一标识符,返回一个 Promise,表示删除操作的结果。

@Args('id') id: string: 这是一个装饰器,表示从客户端传递进来的参数。在这里,id 是通过 Mutation 操作传递给 resolver 的参数,它表示要删除的用户的唯一标识符。

return await this.userService.del(id);: 在方法内部,通过调用 this.userService.del 方法,使用了注入的 UserService 来执行删除用户的操作。传递给 del 方法的参数是用户的唯一标识符 id。

返回值: 删除操作的结果会被封装在一个布尔类型的 Promise 中,表示删除是否成功。在这个例子中,true 可能表示删除成功,false 可能表示删除失败。

这样,当客户端发起删除用户的 Mutation 请求时,会调用 del 方法执行删除操作,并返回删除操作的结果。

在graphql中进行测试

python 复制代码
mutation del($id: String!){
  del(id: $id)
}
json 复制代码
{
  "id": "8dcc8724-3cab-404b-bc61-7e7775774ea5"
}
相关推荐
罗曼蒂克在消亡1 天前
graphql--快速了解graphql特点
后端·graphql
潘多编程1 天前
Spring Boot与GraphQL:现代化API设计
spring boot·后端·graphql
罗曼蒂克在消亡1 天前
GraphQL规范
开发语言·graphql
Spirited_Away4 天前
Nest世界中的AOP
前端·node.js·nestjs
Eric_见嘉11 天前
NestJS 🧑‍🍳 厨子必修课(六):Prisma 集成(下)
前端·后端·nestjs
技术无疆14 天前
【Python】Tartiflette:用 Python 实现的 GraphQL 服务器
服务器·开发语言·后端·python·pygame·graphql·python3.11
_.Switch21 天前
构建高效 Python Web API:RESTful 设计与 GraphQL 实践
开发语言·前端·后端·python·restful·graphql
_.Switch22 天前
Python Web 应用的部署与运维
运维·开发语言·前端·python·restful·graphql
编程乐趣23 天前
Boxed:包含多个.Net项目模板,涵盖了ASP.NET Core API、GraphQL等。
asp.net·.net·graphql
kongxx1 个月前
NestJS中使用Guard实现路由保护
nestjs