从零入门 NestJS:构建你的第一个 REST API(九)GraphQL 集成与实践

178 阅读3分钟

GraphQL 集成与实践

GraphQL 是一种灵活高效的 API 查询语言,允许客户端按需获取数据,极大提升了前后端协作效率。NestJS 提供了对 GraphQL 的一流支持,适合需要灵活数据结构和高性能查询的场景。

GraphQL 基本概念

  • GraphQL:由 Facebook 推出的一种 API 查询语言,支持单接口多资源查询、类型系统、实时订阅等。
  • Schema:定义数据类型、查询(Query)、变更(Mutation)、订阅(Subscription)等。
  • Resolver:解析器,负责处理具体的查询和变更逻辑。
  • DTO/Input:用于参数校验和类型约束。

GraphQL 与 REST 的区别

特性REST APIGraphQL
数据获取多接口多请求单接口按需获取
版本管理需维护多版本Schema 演进无版本
类型系统强类型、自动文档
过/欠载问题常见客户端自定义字段
实时订阅支持较弱原生支持(Subscription)

GraphQL 适合数据结构复杂、前端需求多变、需要高效聚合查询的中大型项目。

安装与环境准备

npm install --save @nestjs/graphql @nestjs/apollo graphql apollo-server-express

其中 @nestjs/apollo 是 NestJS 官方为 Apollo Server 提供的集成包, 让你可以在 NestJS 中无缝使用 Apollo 作为 GraphQL 的底层引擎。 Apollo Server 是当前最流行的 GraphQL 服务端实现,支持强大的开发工具、性能优化和中间件扩展。

在 NestJS 中集成 GraphQL

在主模块中配置 GraphQLModule:

// app.module.ts
import { Module } from '@nestjs/common';
import { GraphQLModule } from '@nestjs/graphql';
import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
import { UserModule } from './user/user.module';

@Module({
  imports: [
    GraphQLModule.forRoot<ApolloDriverConfig>({
      driver: ApolloDriver, // 这里指定了 Apollo 作为 GraphQL 的运行时驱动
      autoSchemaFile: true, // 自动生成 schema.gql
      playground: true,     // 启用可视化调试
    }),
    UserModule,
  ],
})
export class AppModule {}

通过 ApolloDriver,NestJS 能够充分利用 Apollo Server 的生态和功能,如 Playground、订阅、性能监控等。

定义 GraphQL 类型与 Resolver

1. 定义对象类型(Type)

// user/user.type.ts
import { ObjectType, Field, Int } from '@nestjs/graphql';

@ObjectType()
export class UserType {
  @Field(type => Int)
  id: number;

  @Field()
  username: string;

  @Field()
  email: string;
}

2. 定义输入类型(Input)

// user/dto/create-user.input.ts
import { InputType, Field } from '@nestjs/graphql';

@InputType()
export class CreateUserInput {
  @Field()
  username: string;

  @Field()
  email: string;

  @Field()
  password: string;
}

3. 定义 Resolver

// user/user.resolver.ts
import { Resolver, Query, Mutation, Args, Int } from '@nestjs/graphql';
import { UserService } from './user.service';
import { UserType } from './user.type';
import { CreateUserInput } from './dto/create-user.input';

@Resolver(of => UserType)
export class UserResolver {
  constructor(private readonly userService: UserService) {}

  @Query(returns => [UserType])
  async users() {
    return this.userService.findAll();
  }

  @Query(returns => UserType, { nullable: true })
  async user(@Args('id', { type: () => Int }) id: number) {
    return this.userService.findById(id);
  }

  @Mutation(returns => UserType)
  async createUser(@Args('input') input: CreateUserInput) {
    return this.userService.create(input.username, input.password, input.email);
  }
}

典型实战场景:灵活数据查询

前端可通过单一接口灵活查询用户、文章等多种数据,按需获取字段,减少冗余数据和接口数量。

query {
  users {
    id
    username
    email
  }
}

mutation {
  createUser(input: { username: "nest", email: "nest@demo.com", password: "123456" }) {
    id
    username
  }
}

最佳实践与常见坑点

  • 类型定义要与数据库/DTO一致,避免类型不匹配。
  • 合理拆分 Query/Mutation/Subscription,便于维护。
  • 善用 InputType 进行参数校验,提升安全性。
  • 避免 N+1 查询,可用 DataLoader 优化关联查询。
  • GraphQL Playground 不建议在生产环境开启
  • 错误处理要规范,可结合拦截器统一格式。

GraphQL 让 API 更灵活高效,建议多查阅 NestJS GraphQL 文档GraphQL 官方文档 掌握更多高级用法。